From edaa7a1ba1ace689c3c44a3b3820b56fd83945df Mon Sep 17 00:00:00 2001 From: Ichito Nagata Date: Sun, 3 Jun 2018 19:40:33 +0900 Subject: fix env->stack misadjusting --- src/vm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index c9e923ee0..ba2c32972 100644 --- a/src/vm.c +++ b/src/vm.c @@ -141,7 +141,7 @@ stack_init(mrb_state *mrb) } static inline void -envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) +envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t oldsize) { mrb_callinfo *ci = mrb->c->cibase; @@ -151,7 +151,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) mrb_value *st; if (e && MRB_ENV_STACK_SHARED_P(e) && - (st = e->stack) && oldbase <= st && st < oldbase+size) { + (st = e->stack) && oldbase <= st && st < oldbase+oldsize) { ptrdiff_t off = e->stack - oldbase; e->stack = newbase + off; @@ -161,7 +161,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size) e = MRB_PROC_ENV(ci->proc); if (e && MRB_ENV_STACK_SHARED_P(e) && - (st = e->stack) && oldbase <= st && st < oldbase+size) { + (st = e->stack) && oldbase <= st && st < oldbase+oldsize) { ptrdiff_t off = e->stack - oldbase; e->stack = newbase + off; @@ -205,7 +205,7 @@ stack_extend_alloc(mrb_state *mrb, int room) mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } stack_clear(&(newstack[oldsize]), size - oldsize); - envadjust(mrb, oldbase, newstack, size); + envadjust(mrb, oldbase, newstack, oldsize); mrb->c->stbase = newstack; mrb->c->stack = mrb->c->stbase + off; mrb->c->stend = mrb->c->stbase + size; -- cgit v1.2.3 From c2b2bec9e239cb9bca1186e546fe6483ca9e2024 Mon Sep 17 00:00:00 2001 From: Ichito Nagata Date: Wed, 6 Jun 2018 15:04:58 +0900 Subject: Revert "Fix heap use after free on mruby-aws-sigv4." This reverts commit b8869498b7b1458af1cf2a5ccc7644849f826230. --- src/vm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index ba2c32972..f1eae5ba5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -528,8 +528,6 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) return MRB_PROC_CFUNC(p)(mrb, self); } ci->nregs = p->body.irep->nregs; - ci->env = MRB_PROC_ENV(p); - if (ci->env) ci->env->stack[0] = self; if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; if (ci->nregs < keep) { -- cgit v1.2.3 From ff0a4f78674308b7643db1da9b9dc591f25c21d0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 7 Jun 2018 15:55:20 +0900 Subject: Export `stack_extend` function (renamed `mrb_stack_extend`); fix #3219 This change is required to support #4038. --- include/mruby.h | 1 + src/vm.c | 46 +++++++++++++++++++++++----------------------- 2 files changed, 24 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 3b953a327..8c4f9280b 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1235,6 +1235,7 @@ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib); * @mrbgem mruby-fiber */ #define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError")) +MRB_API void mrb_stack_extend(mrb_state*, int); /* memory pool implementation */ typedef struct mrb_pool mrb_pool; diff --git a/src/vm.c b/src/vm.c index ba2c32972..3ebdea310 100644 --- a/src/vm.c +++ b/src/vm.c @@ -217,8 +217,8 @@ stack_extend_alloc(mrb_state *mrb, int room) } } -static inline void -stack_extend(mrb_state *mrb, int room) +MRB_API void +mrb_stack_extend(mrb_state *mrb, int room) { if (mrb->c->stack + room >= mrb->c->stend) { stack_extend_alloc(mrb, room); @@ -446,7 +446,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_missing(mrb, mid, self, args); } mrb_ary_unshift(mrb, args, mrb_symbol_value(mid)); - stack_extend(mrb, n+2); + mrb_stack_extend(mrb, n+2); mrb->c->stack[n+1] = args; argc = -1; } @@ -464,11 +464,11 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc } if (MRB_METHOD_CFUNC_P(m)) { ci->nregs = (int)(argc + 2); - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); } else if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - stack_extend(mrb, ci->nregs+2); + mrb_stack_extend(mrb, ci->nregs+2); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; @@ -478,7 +478,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->proc = p; if (argc < 0) argc = 1; ci->nregs = (int)(p->body.irep->nregs + argc); - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); } if (voff >= 0) { argv = mrb->c->stbase + voff; @@ -533,10 +533,10 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; if (ci->nregs < keep) { - stack_extend(mrb, keep); + mrb_stack_extend(mrb, keep); } else { - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); stack_clear(mrb->c->stack+keep, ci->nregs-keep); } @@ -635,14 +635,14 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) ci->argc = 1; ci->mid = ci[-1].mid; if (MRB_PROC_CFUNC_P(p)) { - stack_extend(mrb, 3); + mrb_stack_extend(mrb, 3); mrb->c->stack[0] = self; mrb->c->stack[1] = self; mrb->c->stack[2] = mrb_nil_value(); return MRB_PROC_CFUNC(p)(mrb, self); } ci->nregs = p->body.irep->nregs; - stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; mrb->c->stack[2] = mrb_nil_value(); @@ -749,7 +749,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value ci->acc = CI_ACC_SKIP; mrb->c->stack = mrb->c->stack + n; ci->nregs = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); mrb->c->stack[0] = self; if (argc > 0) { @@ -800,7 +800,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const p = mrb_proc_ptr(b); ci = mrb->c->ci; - stack_extend(mrb, 3); + mrb_stack_extend(mrb, 3); mrb->c->stack[1] = mrb_ary_new_from_values(mrb, argc, argv); mrb->c->stack[2] = mrb_nil_value(); ci->argc = -1; @@ -944,7 +944,7 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac } if (stack_keep > nregs) nregs = stack_keep; - stack_extend(mrb, nregs); + mrb_stack_extend(mrb, nregs); stack_clear(c->stack + stack_keep, nregs - stack_keep); c->stack[0] = self; result = mrb_vm_exec(mrb, proc, irep->iseq); @@ -1373,7 +1373,7 @@ RETRY_TRY_BLOCK: ci->pc = pc; ci->acc = ci[-1].nregs; mrb->c->stack += ci->acc; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); regs[0] = self; pc = irep->iseq; } @@ -1437,7 +1437,7 @@ RETRY_TRY_BLOCK: } if (argc >= 0) { if (a+2 >= irep->nregs) { - stack_extend(mrb, a+3); + mrb_stack_extend(mrb, a+3); } regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); regs[a+2] = blk; @@ -1510,7 +1510,7 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; - stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); pc = irep->iseq; JUMP; } @@ -1571,7 +1571,7 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); if (ci->argc < 0) { if (irep->nregs > 3) { stack_clear(regs+3, irep->nregs-3); @@ -1648,7 +1648,7 @@ RETRY_TRY_BLOCK: mid = missing; if (argc >= 0) { if (a+2 >= ci->nregs) { - stack_extend(mrb, a+3); + mrb_stack_extend(mrb, a+3); } regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); regs[a+2] = blk; @@ -1709,7 +1709,7 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; - stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); pc = irep->iseq; JUMP; } @@ -1967,7 +1967,7 @@ RETRY_TRY_BLOCK: if (ci < ci0) { mrb->c->stack = ci[1].stackent; } - stack_extend(mrb, irep->nregs); + mrb_stack_extend(mrb, irep->nregs); pc = mrb->c->rescue[--ci->ridx]; } else { @@ -2200,10 +2200,10 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; if (ci->argc < 0) { - stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); + mrb_stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); } else { - stack_extend(mrb, irep->nregs); + mrb_stack_extend(mrb, irep->nregs); } pc = irep->iseq; } @@ -2877,7 +2877,7 @@ RETRY_TRY_BLOCK: pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; - stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, ci->nregs); stack_clear(regs+1, ci->nregs-1); pc = irep->iseq; JUMP; -- cgit v1.2.3 From 55edae0226409de25e59922807cb09acb45731a2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 7 Jun 2018 16:17:00 +0900 Subject: Allow `Object#clone` to copy frozen status only; fix #4036 Copying all flags from the original object may overwrite the clone's flags e.g. the embedded flag. --- src/kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index f378004cb..bbe6e8bb7 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -348,7 +348,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c); clone = mrb_obj_value(p); init_copy(mrb, clone, self); - p->flags = mrb_obj_ptr(self)->flags; + p->flags |= mrb_obj_ptr(self)->flags & MRB_FLAG_IS_FROZEN; return clone; } -- cgit v1.2.3 From faa4eaf6803bd11669bc324b4c34e7162286bfa3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 8 Jun 2018 14:13:06 +0900 Subject: `mrb_class_real()` did not work for `BasicObject`; fix #4037 --- src/class.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index c761f46af..a9439d7d7 100644 --- a/src/class.c +++ b/src/class.c @@ -1763,10 +1763,10 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) MRB_API struct RClass* mrb_class_real(struct RClass* cl) { - if (cl == 0) - return NULL; + if (cl == 0) return NULL; while ((cl->tt == MRB_TT_SCLASS) || (cl->tt == MRB_TT_ICLASS)) { cl = cl->super; + if (cl == 0) return NULL; } return cl; } -- cgit v1.2.3 From a9b740b36b4518552d61f349afc02c325413d2ad Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 Jun 2018 14:50:03 +0900 Subject: Retrieve `b` operand from the instruction (for debugging); ref #4020 --- src/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 59ae57c32..552bc8072 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1398,6 +1398,7 @@ RETRY_TRY_BLOCK: CASE(OP_SEND) { /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ int a = GETARG_A(i); + int b = GETARG_B(i); int n = GETARG_C(i); int argc = (n == CALL_MAXARGS) ? -1 : n; int bidx = (argc < 0) ? a+2 : a+n+1; @@ -1405,7 +1406,7 @@ RETRY_TRY_BLOCK: struct RClass *c; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; - mrb_sym mid = syms[GETARG_B(i)]; + mrb_sym mid = syms[b]; mrb_assert(bidx < ci->nregs); -- cgit v1.2.3 From 23a4e7149dc4253caf5ed0a528ffe5c21c4afb80 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 Jun 2018 14:50:42 +0900 Subject: Revert "No longer need to insert write barriers for fibers." This reverts commit c6736357a72049a0eb2a31ccabcc3cd2baba7c9e. The assumption was wrong and caused the issue; fix #4020 --- mrbgems/mruby-fiber/src/fiber.c | 3 +++ src/vm.c | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index b88fa4949..bff8726a7 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -175,6 +175,9 @@ fiber_check_cfunc(mrb_state *mrb, struct mrb_context *c) static void fiber_switch_context(mrb_state *mrb, struct mrb_context *c) { + if (mrb->c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); + } c->status = MRB_FIBER_RUNNING; mrb->c = c; } diff --git a/src/vm.c b/src/vm.c index 552bc8072..43efaa669 100644 --- a/src/vm.c +++ b/src/vm.c @@ -949,7 +949,12 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac if (c->ci - c->cibase > cioff) { c->ci = c->cibase + cioff; } - mrb->c = c; + if (mrb->c != c) { + if (mrb->c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); + } + mrb->c = c; + } return result; } @@ -1942,6 +1947,9 @@ RETRY_TRY_BLOCK: while (c->eidx > ci->epos) { ecall_adjust(); } + if (c->fib) { + mrb_write_barrier(mrb, (struct RBasic*)c->fib); + } mrb->c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; -- cgit v1.2.3 From ba090a46af56355d8c4a458f8000cceae26d1c4f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 14 Jun 2018 11:25:12 +0900 Subject: Need to add a write barrier for ranges; fix #4042 Ranges are almost immutable but `initialize` and `initialize_copy` modify the receiver so that we need to add a write barrier. --- src/range.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/range.c b/src/range.c index 0360b48ae..e45308d35 100644 --- a/src/range.c +++ b/src/range.c @@ -120,6 +120,7 @@ range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bo } r->edges->beg = beg; r->edges->end = end; + mrb_write_barrier(mrb, (struct RBasic*)r); } /* * call-seq: -- cgit v1.2.3 From 97933665b6c427348983bab936a5d855f1384712 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 14 Jun 2018 11:42:34 +0900 Subject: Restore GC arena after raised exceptions; ref #4042 --- src/vm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 43efaa669..7a436828a 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1002,6 +1002,7 @@ RETRY_TRY_BLOCK: if (exc_catched) { exc_catched = FALSE; + mrb_gc_arena_restore(mrb, ai); if (mrb->exc && mrb->exc->tt == MRB_TT_BREAK) goto L_BREAK; goto L_RAISE; -- cgit v1.2.3 From 7e798405874ee3a4e3019436d8560641a5048dd3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 22 Jun 2018 12:03:52 +0900 Subject: initialize a local variable to avoid warning --- src/enum.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/enum.c b/src/enum.c index ea05777b3..03508953e 100644 --- a/src/enum.c +++ b/src/enum.c @@ -27,6 +27,8 @@ enum_update_hash(mrb_state *mrb, mrb_value self) #endif else { mrb_raise(mrb, E_TYPE_ERROR, "can't calculate hash"); + /* not reached */ + hv = 0; } hash ^= (hv << (index % 16)); -- cgit v1.2.3 From 695f29cd604787f43be1af16e38d13610bf8312b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 27 Jun 2018 16:32:24 +0900 Subject: Add negative check in `mrb_str_resize`; fix #4062 --- src/string.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index 5cca6d460..fd09e05dc 100644 --- a/src/string.c +++ b/src/string.c @@ -708,6 +708,9 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) mrb_int slen; struct RString *s = mrb_str_ptr(str); + if (len < 0) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative (or overflowed) string size"); + } mrb_str_modify(mrb, s); slen = RSTR_LEN(s); if (len != slen) { -- cgit v1.2.3 From adb1eae912659d680a9c5b7832e22cf73d36a69a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Jun 2018 22:40:24 +0900 Subject: Use `mrb_raise()` instead of `mrb_raisef()`; ref #4062 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index fd09e05dc..b7abfb762 100644 --- a/src/string.c +++ b/src/string.c @@ -709,7 +709,7 @@ mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) struct RString *s = mrb_str_ptr(str); if (len < 0) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative (or overflowed) string size"); + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative (or overflowed) string size"); } mrb_str_modify(mrb, s); slen = RSTR_LEN(s); -- cgit v1.2.3 From 891839b976c75c77f238931123ac472e3284e95d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 May 2018 15:19:06 +0900 Subject: New bytecode implementation of mruby VM. --- .gitignore | 1 + doc/opcode.md | 260 +++++ include/mruby.h | 16 +- include/mruby/class.h | 3 +- include/mruby/compile.h | 2 + include/mruby/irep.h | 2 +- include/mruby/opcode.h | 186 +--- include/mruby/ops.h | 116 +++ mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 2 +- mrbgems/mruby-compiler/core/codegen.c | 1351 +++++++++++++------------- mrbgems/mruby-compiler/core/parse.y | 15 + mrbgems/mruby-eval/src/eval.c | 112 ++- mrbgems/mruby-method/src/method.c | 6 +- mrbgems/mruby-proc-ext/src/proc.c | 12 +- mrbgems/mruby-string-ext/src/string.c | 4 +- src/class.c | 8 +- src/codedump.c | 772 ++++++++------- src/kernel.c | 2 +- src/load.c | 2 +- src/proc.c | 10 +- src/vm.c | 986 ++++++++----------- 21 files changed, 2072 insertions(+), 1796 deletions(-) create mode 100644 doc/opcode.md create mode 100644 include/mruby/ops.h (limited to 'src') diff --git a/.gitignore b/.gitignore index bccfaf218..9c34b5f29 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ .DS_Store .ccmalloc .svn +.vscode /.git cscope.files cscope.out diff --git a/doc/opcode.md b/doc/opcode.md new file mode 100644 index 000000000..d904256e5 --- /dev/null +++ b/doc/opcode.md @@ -0,0 +1,260 @@ +<<<<<<< HEAD +# The new bytecode + +We will reimplement VM to use 8bit instruction code. By +bytecode, we mean real byte code. The whole purpose is +reducing the memory consumption of mruby VM. + +# Instructions + +Instructions are bytes. There can be 256 instructions. Currently we +have 94 instructions. Instructions can take 0 to 3 operands. + +## operands + +The size of operands can be either 8bits, 16bits or 24bits. +In the table.1 below, the second field describes the size (and +sign) of operands. + +* B: 8bit +* sB: signed 8bit +* S: 16bit +* sS: signed 16bit +* W: 24bit + +First two byte operands may be extended to 16bit. When those byte +operands are bigger than 256, the instruction will be prefixed by +`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand +is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit). + +For instructions marked by `'`, `OP_EXT1` can be prefixed. For those +with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. + +## table.1 Instruction Table + +|Instruction Name |Operand type |Semantics +|-----------------|-------------|----------------- +|OP_NOP | - | +|OP_MOVE" |BB |R(a) = R(b) +|OP_LOADL" |BB |R(a) = Pool(b) +|OP_LOADI" |BsB |R(a) = mrb_int(b) +|OP_LOADI_0' |B |R(a) = 0 +|OP_LOADI_1' |B |R(a) = 1 +|OP_LOADI_2' |B |R(a) = 2 +|OP_LOADI_3' |B |R(a) = 3 +|OP_LOADSYM" |BB |R(a) = Syms(b) +|OP_LOADNIL' |B |R(a) = nil +|OP_LOADSELF' |B |R(a) = self +|OP_LOADT' |B |R(a) = true +|OP_LOADF' |B |R(a) = false +|OP_GETGV" |BB |R(a) = getglobal(Syms(b)) +|OP_SETGV" |BB |setglobal(Syms(b), R(a)) +|OP_GETSV" |BB |R(a) = Special[b] +|OP_SETSV" |BB |Special[b] = R(a) +|OP_GETIV" |BB |R(a) = ivget(Syms(b)) +|OP_SETIV" |BB |ivset(Syms(b),R(a)) +|OP_GETCV" |BB |R(a) = cvget(Syms(b)) +|OP_SETCV" |BB |cvset(Syms(b),R(a)) +|OP_GETCONST" |BB |R(a) = constget(Syms(b)) +|OP_SETCONST" |BB |constset(Syms(b),R(a)) +|OP_GETMCNST" |BB |R(a) = R(a)::Syms(b) +|OP_SETMCNST" |BB |R(a+1)::Syms(b) = R(a) +|OP_GETUPVAR' |BBB |R(a) = uvget(b,c) +|OP_SETUPVAR' |BBB |uvset(b,c,R(a)) +|OP_JMP |S |pc+=a +|OP_JMPIF' |SB |if R(b) pc+=a +|OP_JMPNOT' |SB |if !R(b) pc+=a +|OP_ONERR |sS |rescue_push(pc+a) +|OP_EXCEPT' |B |R(a) = exc +|OP_RESCUE" |BB |R(b) = R(a).isa?(R(b)) +|OP_POPERR |B |a.times{rescue_pop()} +|OP_RAISE' |B |raise(R(a)) +|OP_EPUSH' |B |ensure_push(SEQ[a]) +|OP_EPOP |B |A.times{ensure_pop().call} +|OP_SENDV" |BB |R(a) = call(R(a),Syms(b),*R(a+1)) +|OP_SENDVB" |BB |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) +|OP_SEND" |BBB |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) +|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) +|OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) +|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) +|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) +|OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) +|OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo +|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo +|OP_KDICT' |B |R(a) = kdict # todo +|OP_RETURN' |B |return R(a) (normal) +|OP_RETURN_BLK' |B |return R(a) (in-block return) +|OP_BREAK' |B |break R(a) +|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) +|OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) +|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) +|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) +|OP_SUBI" |BB |R(a) = R(a)-C (Syms[b]=:-) +|OP_MUL" |BB |R(a) = R(a)*R(a+1) (Syms[b]=:*) +|OP_DIV" |BB |R(a) = R(a)/R(a+1) (Syms[b]=:/) +|OP_EQ" |BB |R(a) = R(a)==R(a+1) (Syms[b]=:==) +|OP_LT" |BB |R(a) = R(a)R(a+1) (Syms[b]=:>) +|OP_GE" |BB |R(a) = R(a)>=R(a+1) (Syms[b]=:>=) +|OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b)) +|OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c)) +|OP_ARYCAT' |B |ary_cat(R(a),R(a+1)) +|OP_ARYPUSH' |B |ary_push(R(a),R(a+1)) +|OP_AREF' |BB |R(a) = R(a)[b] +|OP_ASET' |BB |R(a)[b] = R(a+1) +|OP_APOST' |BB |*R(a),R(A+1)..R(A+C) = R(a)[B..] +|OP_STRING" |BB |R(a) = str_dup(Lit(b)) +|OP_STRCAT' |B |str_cat(R(a),R(a+1)) +|OP_HASH' |BB |R(a) = hash_new(R(a),R(a+1)..R(a+b)) +|OP_HASHADD' |BB |R(a) = hash_push(R(a),R(a+1)..R(a+b)) +|OP_LAMBDA" |BB |R(a) = lambda(SEQ[b],OP_L_LAMBDA) +|OP_BLOCK" |BB |R(a) = lambda(SEQ[b],OP_L_BLOCK) +|OP_METHOD" |BB |R(a) = lambda(SEQ[b],OP_L_METHOD) +|OP_RANGE_INC' |B |R(a) = range_new(R(a),R(a+1),FALSE) +|OP_RANGE_EXC' |B |R(a) = range_new(R(a),R(a+1),TRUE) +|OP_OCLASS' |B |R(a) = ::Object +|OP_CLASS" |BB |R(a) = newclass(R(a),Syms(b),R(a+1)) +|OP_MODULE" |BB |R(a) = newmodule(R(a),Syms(b)) +|OP_EXEC" |BB |R(a) = blockexec(R(a),SEQ[b]) +|OP_DEF" |BB |R(a).newmethod(Syms(b),R(a+1)) +|OP_ALIAS' |B |alias_method(R(a),R(a+1),R(a+2)) +|OP_UNDEF" |BB |undef_method(R(a),Syms(b)) +|OP_SCLASS' |B |R(a) = R(a).singleton_class +|OP_TCLASS' |B |R(a) = target_class +|OP_ERR' |B |raise(RuntimeError, Lit(Bx)) +|OP_EXT1 |- |make 1st operand 16bit +|OP_EXT2 |- |make 2nd operand 16bit +|OP_EXT3 |- |make 1st and 2nd operands 16bit +|OP_STOP |- |stop VM +||||||| parent of b6821923... New bytecode implementation of mruby VM. +======= +# The new bytecode + +We will reimplement VM to use 8bit instruction code. By +bytecode, we mean real byte code. The whole purpose is +reducing the memory consumption of mruby VM. + +# Instructions + +Instructions are bytes. There can be 256 instructions. Currently we +have 94 instructions. Instructions can take 0 to 3 operands. + +## operands + +The size of operands can be either 8bits, 16bits or 24bits. +In the table.1 below, the second field describes the size (and +sign) of operands. + +* B: 8bit +* sB: signed 8bit +* S: 16bit +* sS: signed 16bit +* W: 24bit + +First two byte operands may be extended to 16bit. When those byte +operands are bigger than 256, the instruction will be prefixed by +`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand +is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit). + +For instructions marked by `'`, `OP_EXT1` can be prefixed. For those +with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. + +## table.1 Instruction Table + +|Instruction Name |Operand type |Semantics +|-----------------|-------------|----------------- +|OP_NOP | - | +|OP_MOVE" |BB |R(a) = R(b) +|OP_LOADL" |BB |R(a) = Pool(b) +|OP_LOADI" |BsB |R(a) = mrb_int(b) +|OP_LOADI_0' |B |R(a) = 0 +|OP_LOADI_1' |B |R(a) = 1 +|OP_LOADI_2' |B |R(a) = 2 +|OP_LOADI_3' |B |R(a) = 3 +|OP_LOADSYM" |BB |R(a) = Syms(b) +|OP_LOADNIL' |B |R(a) = nil +|OP_LOADSELF' |B |R(a) = self +|OP_LOADT' |B |R(a) = true +|OP_LOADF' |B |R(a) = false +|OP_GETGV" |BB |R(a) = getglobal(Syms(b)) +|OP_SETGV" |BB |setglobal(Syms(b), R(a)) +|OP_GETSV" |BB |R(a) = Special[b] +|OP_SETSV" |BB |Special[b] = R(a) +|OP_GETIV" |BB |R(a) = ivget(Syms(b)) +|OP_SETIV" |BB |ivset(Syms(b),R(a)) +|OP_GETCV" |BB |R(a) = cvget(Syms(b)) +|OP_SETCV" |BB |cvset(Syms(b),R(a)) +|OP_GETCONST" |BB |R(a) = constget(Syms(b)) +|OP_SETCONST" |BB |constset(Syms(b),R(a)) +|OP_GETMCNST" |BB |R(a) = R(a)::Syms(b) +|OP_SETMCNST" |BB |R(a+1)::Syms(b) = R(a) +|OP_GETUPVAR' |BBB |R(a) = uvget(b,c) +|OP_SETUPVAR' |BBB |uvset(b,c,R(a)) +|OP_JMP |S |pc+=a +|OP_JMPIF' |SB |if R(b) pc+=a +|OP_JMPNOT' |SB |if !R(b) pc+=a +|OP_ONERR |sS |rescue_push(pc+a) +|OP_EXCEPT' |B |R(a) = exc +|OP_RESCUE" |BB |R(b) = R(a).isa?(R(b)) +|OP_POPERR |B |a.times{rescue_pop()} +|OP_RAISE' |B |raise(R(a)) +|OP_EPUSH' |B |ensure_push(SEQ[a]) +|OP_EPOP |B |A.times{ensure_pop().call} +|OP_SENDV" |BB |R(a) = call(R(a),Syms(b),*R(a+1)) +|OP_SENDVB" |BB |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) +|OP_SEND" |BBB |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) +|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) +|OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) +|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) +|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) +|OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) +|OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo +|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo +|OP_KDICT' |B |R(a) = kdict # todo +|OP_RETURN' |B |return R(a) (normal) +|OP_RETURN_BLK' |B |return R(a) (in-block return) +|OP_BREAK' |B |break R(a) +|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) +|OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) +|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) +|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) +|OP_SUBI" |BB |R(a) = R(a)-C (Syms[b]=:-) +|OP_MUL" |BB |R(a) = R(a)*R(a+1) (Syms[b]=:*) +|OP_DIV" |BB |R(a) = R(a)/R(a+1) (Syms[b]=:/) +|OP_EQ" |BB |R(a) = R(a)==R(a+1) (Syms[b]=:==) +|OP_LT" |BB |R(a) = R(a)R(a+1) (Syms[b]=:>) +|OP_GE" |BB |R(a) = R(a)>=R(a+1) (Syms[b]=:>=) +|OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b)) +|OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c)) +|OP_ARYCAT' |B |ary_cat(R(a),R(a+1)) +|OP_ARYPUSH' |B |ary_push(R(a),R(a+1)) +|OP_AREF' |BB |R(a) = R(a)[b] +|OP_ASET' |BB |R(a)[b] = R(a+1) +|OP_APOST' |BB |*R(a),R(A+1)..R(A+C) = R(a)[B..] +|OP_STRING" |BB |R(a) = str_dup(Lit(b)) +|OP_STRCAT' |B |str_cat(R(a),R(a+1)) +|OP_HASH' |BB |R(a) = hash_new(R(a),R(a+1)..R(a+b)) +|OP_HASHADD' |BB |R(a) = hash_push(R(a),R(a+1)..R(a+b)) +|OP_LAMBDA" |BB |R(a) = lambda(SEQ[b],OP_L_LAMBDA) +|OP_BLOCK" |BB |R(a) = lambda(SEQ[b],OP_L_BLOCK) +|OP_METHOD" |BB |R(a) = lambda(SEQ[b],OP_L_METHOD) +|OP_RANGE_INC' |B |R(a) = range_new(R(a),R(a+1),FALSE) +|OP_RANGE_EXC' |B |R(a) = range_new(R(a),R(a+1),TRUE) +|OP_OCLASS' |B |R(a) = ::Object +|OP_CLASS" |BB |R(a) = newclass(R(a),Syms(b),R(a+1)) +|OP_MODULE" |BB |R(a) = newmodule(R(a),Syms(b)) +|OP_EXEC" |BB |R(a) = blockexec(R(a),SEQ[b]) +|OP_DEF" |BB |R(a).newmethod(Syms(b),R(a+1)) +|OP_ALIAS' |B |alias_method(R(a),R(a+1),R(a+2)) +|OP_UNDEF" |BB |undef_method(R(a),Syms(b)) +|OP_SCLASS' |B |R(a) = R(a).singleton_class +|OP_TCLASS' |B |R(a) = target_class +|OP_ERR' |B |raise(RuntimeError, Lit(Bx)) +|OP_EXT1 |- |make 1st operand 16bit +|OP_EXT2 |- |make 2nd operand 16bit +|OP_EXT3 |- |make 1st and 2nd operands 16bit +|OP_STOP |- |stop VM +>>>>>>> b6821923... New bytecode implementation of mruby VM. diff --git a/include/mruby.h b/include/mruby.h index b0bfe78b5..7cbc690b3 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -93,7 +93,7 @@ */ MRB_BEGIN_DECL -typedef uint32_t mrb_code; +typedef uint8_t mrb_code; /** * Required arguments signature type. @@ -123,9 +123,9 @@ typedef struct { mrb_sym mid; struct RProc *proc; mrb_value *stackent; - int nregs; - int ridx; - int epos; + uint16_t nregs; + uint16_t ridx; + uint16_t epos; struct REnv *env; mrb_code *pc; /* return address */ mrb_code *err; /* error position */ @@ -152,10 +152,10 @@ struct mrb_context { mrb_callinfo *ci; mrb_callinfo *cibase, *ciend; - mrb_code **rescue; /* exception handler stack */ + uint16_t *rescue; /* exception handler stack */ int rsize; struct RProc **ensure; /* ensure handler stack */ - int esize, eidx; + uint8_t esize, eidx; enum mrb_fiber_state status; mrb_bool vmexec; @@ -486,9 +486,10 @@ MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_ * } * @param [mrb_state*] mrb_state* The mruby state reference. * @param [struct RClass*] RClass* A class the method will be undefined from. - * @param [const char*] constchar* The name of the method to be undefined. + * @param [const char] const char* The name of the method to be undefined. */ MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*); +MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym); /** * Undefine a class method. @@ -1197,7 +1198,6 @@ typedef enum call_type { CALL_TYPE_MAX } call_type; -MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2); MRB_API const char *mrb_class_name(mrb_state *mrb, struct RClass* klass); MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val); diff --git a/include/mruby/class.h b/include/mruby/class.h index ea35d8e17..706a4d37c 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -76,7 +76,8 @@ MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t); MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec); -MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b); +MRB_API void mrb_alias_method(mrb_state*, struct RClass *c, mrb_sym a, mrb_sym b); +MRB_API void mrb_define_alias(mrb_state*, struct RClass *c, const char* a, const char* b); MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym); diff --git a/include/mruby/compile.h b/include/mruby/compile.h index d7d029616..a85460415 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -33,6 +33,7 @@ typedef struct mrbc_context { mrb_bool no_exec:1; mrb_bool keep_lv:1; mrb_bool no_optimize:1; + mrb_bool on_eval:1; size_t parser_nerr; } mrbc_context; @@ -151,6 +152,7 @@ struct mrb_parser_state { mrb_ast_node *tree; mrb_bool no_optimize:1; + mrb_bool on_eval:1; mrb_bool capture_errors:1; struct mrb_parser_message error_buffer[10]; struct mrb_parser_message warn_buffer[10]; diff --git a/include/mruby/irep.h b/include/mruby/irep.h index ad227be5d..c98d008db 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -44,7 +44,7 @@ typedef struct mrb_irep { uint16_t *lines; struct mrb_irep_debug_info* debug_info; - int ilen, plen, slen, rlen, refcnt; + uint16_t ilen, plen, slen, rlen, refcnt; } mrb_irep; #define MRB_ISEQ_NO_FREE 1 diff --git a/include/mruby/opcode.h b/include/mruby/opcode.h index a5e3af158..d513ca472 100644 --- a/include/mruby/opcode.h +++ b/include/mruby/opcode.h @@ -7,145 +7,10 @@ #ifndef MRUBY_OPCODE_H #define MRUBY_OPCODE_H -#define MAXARG_Bx (0xffff) -#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ - -/* instructions: packed 32 bit */ -/* ------------------------------- */ -/* A:B:C:OP = 9: 9: 7: 7 */ -/* A:Bx:OP = 9:16: 7 */ -/* Ax:OP = 25: 7 */ -/* A:Bz:Cz:OP = 9:14: 2: 7 */ - -#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f)) -#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff)) -#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff)) -#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f)) -#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff)) -#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx)) -#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff)) -#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1)))) -#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1)))) -#define GETARG_b(i) GETARG_UNPACK_b(i,14,2) -#define GETARG_c(i) GETARG_UNPACK_c(i,14,2) - -#define MKOPCODE(op) ((op) & 0x7f) -#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23) -#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14) -#define MKARG_C(c) (((c) & 0x7f) << 7) -#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7) -#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx) -#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7) -#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<R(A+1) (Syms[B]=:>,C=1) */ - OP_GE,/* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) */ - - OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ - OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */ - OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */ - OP_AREF,/* A B C R(A) := R(B)[C] */ - OP_ASET,/* A B C R(B)[C] := R(A) */ - OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */ - - OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */ - OP_STRCAT,/* A B str_cat(R(A),R(B)) */ - - OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ - OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */ - OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */ - - OP_OCLASS,/* A R(A) := ::Object */ - OP_CLASS,/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ - OP_MODULE,/* A B R(A) := newmodule(R(A),Syms(B)) */ - OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ - OP_METHOD,/* A B R(A).newmethod(Syms(B),R(A+1)) */ - OP_SCLASS,/* A B R(A) := R(B).singleton_class */ - OP_TCLASS,/* A R(A) := target_class */ - - OP_DEBUG,/* A B C print R(A),R(B),R(C) */ - OP_STOP,/* stop VM */ - OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */ - - OP_RSVD1,/* reserved instruction #1 */ - OP_RSVD2,/* reserved instruction #2 */ - OP_RSVD3,/* reserved instruction #3 */ - OP_RSVD4,/* reserved instruction #4 */ - OP_RSVD5,/* reserved instruction #5 */ +enum mrb_insn { +#define OPCODE(x,_) OP_ ## x, +#include "mruby/ops.h" +#undef OPCODE }; #define OP_L_STRICT 1 @@ -158,4 +23,47 @@ enum { #define OP_R_BREAK 1 #define OP_R_RETURN 2 +#define PEEK_B(pc) (*(pc)) +#define PEEK_S(pc) ((pc)[0]<<8|(pc)[1]) +#define PEEK_W(pc) ((pc)[0]<<16|(pc)[1]<<8|(pc)[2]) + +#define READ_B() PEEK_B(pc++) +#define READ_S() (pc+=2, PEEK_S(pc-2)) +#define READ_W() (pc+=3, PEEK_W(pc-3)) + +#define FETCH_Z() /* nothing */ +#define FETCH_B() do {a=READ_B();} while (0) +#define FETCH_BB() do {a=READ_B(); b=READ_B();} while (0) +#define FETCH_BBB() do {a=READ_B(); b=READ_B(); c=READ_B();} while (0) +#define FETCH_BS() do {a=READ_B(); b=READ_S();} while (0) +#define FETCH_S() do {a=READ_S();} while (0) +#define FETCH_W() do {a=READ_W();} while (0) + +/* with OP_EXT1 (1st 16bit) */ +#define FETCH_Z_1() FETCH_Z() +#define FETCH_B_1() FETCH_S() +#define FETCH_BB_1() do {a=READ_S(); b=READ_B();} while (0) +#define FETCH_BBB_1() do {a=READ_S(); b=READ_B(); c=READ_B();} while (0) +#define FETCH_BS_1() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_S_1() FETCH_S() +#define FETCH_W_1() FETCH_W() + +/* with OP_EXT2 (2nd 16bit) */ +#define FETCH_Z_2() FETCH_Z() +#define FETCH_B_2() FETCH_B() +#define FETCH_BB_2() do {a=READ_B(); b=READ_S();} while (0) +#define FETCH_BBB_2() do {a=READ_B(); b=READ_S(); c=READ_B();} while (0) +#define FETCH_BS_2() FETCH_BS() +#define FETCH_S_2() FETCH_S() +#define FETCH_W_2() FETCH_W() + +/* with OP_EXT3 (1st & 2nd 16bit) */ +#define FETCH_Z_3() FETCH_Z() +#define FETCH_B_3() FETCH_B() +#define FETCH_BB_3() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_BBB_3() do {a=READ_S(); b=READ_S(); c=READ_B();} while (0) +#define FETCH_BS_3() do {a=READ_S(); b=READ_S();} while (0) +#define FETCH_S_3() FETCH_S() +#define FETCH_W_3() FETCH_W() + #endif /* MRUBY_OPCODE_H */ diff --git a/include/mruby/ops.h b/include/mruby/ops.h new file mode 100644 index 000000000..882ad6f25 --- /dev/null +++ b/include/mruby/ops.h @@ -0,0 +1,116 @@ +/* operand types: + + Z: no operand (Z,Z,Z,Z) + + B: 8bit (B,S,B,B) + + BB: 8+8bit (BB,SB,BS,SS) + + BBB: 8+8+8bit (BBB,SBB,BSB,SSB) + + BS: 8+16bit (BS,SS,BS,BS) + + S: 16bit (S,S,S,S) + + W: 24bit (W,W,W,W) +*/ + +/*----------------------------------------------------------------------- +operation code operands semantics +------------------------------------------------------------------------*/ +OPCODE(NOP, Z) /* no operation */ +OPCODE(MOVE, BB) /* R(a) = R(b) */ +OPCODE(LOADL, BB) /* R(a) = Pool(b) */ +OPCODE(LOADI, BB) /* R(a) = mrb_int(b) */ +OPCODE(LOADINEG, BB) /* R(a) = mrb_int(-b) */ +OPCODE(LOADI__1, B) /* R(a) = mrb_int(-1) */ +OPCODE(LOADI_0, B) /* R(a) = mrb_int(0) */ +OPCODE(LOADI_1, B) /* R(a) = mrb_int(1) */ +OPCODE(LOADI_2, B) /* R(a) = mrb_int(2) */ +OPCODE(LOADI_3, B) /* R(a) = mrb_int(3) */ +OPCODE(LOADI_4, B) /* R(a) = mrb_int(4) */ +OPCODE(LOADI_5, B) /* R(a) = mrb_int(5) */ +OPCODE(LOADI_6, B) /* R(a) = mrb_int(6) */ +OPCODE(LOADI_7, B) /* R(a) = mrb_int(7) */ +OPCODE(LOADSYM, BB) /* R(a) = Syms(b) */ +OPCODE(LOADNIL, B) /* R(a) = nil */ +OPCODE(LOADSELF, B) /* R(a) = self */ +OPCODE(LOADT, B) /* R(a) = true */ +OPCODE(LOADF, B) /* R(a) = false */ +OPCODE(GETGV, BB) /* R(a) = getglobal(Syms(b)) */ +OPCODE(SETGV, BB) /* setglobal(Syms(b), R(a)) */ +OPCODE(GETSV, BB) /* R(a) = Special[Syms(b)] */ +OPCODE(SETSV, BB) /* Special[Syms(b)] = R(a) */ +OPCODE(GETIV, BB) /* R(a) = ivget(Syms(b)) */ +OPCODE(SETIV, BB) /* ivset(Syms(b),R(a)) */ +OPCODE(GETCV, BB) /* R(a) = cvget(Syms(b)) */ +OPCODE(SETCV, BB) /* cvset(Syms(b),R(a)) */ +OPCODE(GETCONST, BB) /* R(a) = constget(Syms(b)) */ +OPCODE(SETCONST, BB) /* constset(Syms(b),R(a)) */ +OPCODE(GETMCNST, BB) /* R(a) = R(a)::Syms(b) */ +OPCODE(SETMCNST, BB) /* R(a+1)::Syms(b) = R(a) */ +OPCODE(GETUPVAR, BBB) /* R(a) = uvget(b,c) */ +OPCODE(SETUPVAR, BBB) /* uvset(b,c,R(a)) */ +OPCODE(JMP, S) /* pc=a */ +OPCODE(JMPIF, BS) /* if R(b) pc=a */ +OPCODE(JMPNOT, BS) /* if !R(b) pc=a */ +OPCODE(JMPNIL, BS) /* if R(b)==nil pc=a */ +OPCODE(ONERR, S) /* rescue_push(a) */ +OPCODE(EXCEPT, B) /* R(a) = exc */ +OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */ +OPCODE(POPERR, B) /* a.times{rescue_pop()} */ +OPCODE(RAISE, B) /* raise(R(a)) */ +OPCODE(EPUSH, B) /* ensure_push(SEQ[a]) */ +OPCODE(EPOP, B) /* A.times{ensure_pop().call} */ +OPCODE(SENDV, BB) /* R(a) = call(R(a),Syms(b),*R(a+1)) */ +OPCODE(SENDVB, BB) /* R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) */ +OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) */ +OPCODE(SENDB, BBB) /* R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) */ +OPCODE(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */ +OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */ +OPCODE(ARGARY, BS) /* R(a) = argument array (16=6:1:5:4) */ +OPCODE(ENTER, W) /* arg setup according to flags (23=5:5:1:5:5:1:1) */ +OPCODE(KARG, BB) /* R(a) = kdict[Syms(Bx)] # todo */ +OPCODE(KARG2, BB) /* R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo */ +OPCODE(KDICT, B) /* R(a) = kdict # todo */ +OPCODE(RETURN, B) /* return R(a) (normal) */ +OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ +OPCODE(BREAK, B) /* break R(a) */ +OPCODE(BLKPUSH, BS) /* R(a) = block (16=6:1:5:4) */ +OPCODE(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */ +OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (Syms[b]=:+) */ +OPCODE(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */ +OPCODE(SUBI, BBB) /* R(a) = R(a)-C (Syms[b]=:-) */ +OPCODE(MUL, BB) /* R(a) = R(a)*R(a+1) (Syms[b]=:*) */ +OPCODE(DIV, BB) /* R(a) = R(a)/R(a+1) (Syms[b]=:/) */ +OPCODE(EQ, BB) /* R(a) = R(a)==R(a+1) (Syms[b]=:==) */ +OPCODE(LT, BB) /* R(a) = R(a)R(a+1) (Syms[b]=:>) */ +OPCODE(GE, BB) /* R(a) = R(a)>=R(a+1) (Syms[b]=:>=) */ +OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */ +OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */ +OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */ +OPCODE(ARYPUSH, B) /* ary_push(R(a),R(a+1)) */ +OPCODE(ARYDUP, B) /* R(a) = ary_dup(R(a)) */ +OPCODE(AREF, BBB) /* R(a) = R(b)[c] */ +OPCODE(ASET, BBB) /* R(a)[c] = R(b) */ +OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+C) = R(a)[b..] */ +OPCODE(INTERN, B) /* R(a) = intern(R(a)) */ +OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */ +OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */ +OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b)) */ +OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b)) */ +OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */ +OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */ +OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */ +OPCODE(RANGE_INC, B) /* R(a) = range_new(R(a),R(a+1),FALSE) */ +OPCODE(RANGE_EXC, B) /* R(a) = range_new(R(a),R(a+1),TRUE) */ +OPCODE(OCLASS, B) /* R(a) = ::Object */ +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),SEQ[b]) */ +OPCODE(DEF, BB) /* R(a).newmethod(Syms(b),R(a+1)) */ +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 */ +OPCODE(TCLASS, B) /* R(a) = target_class */ +OPCODE(DEBUG, BBB) /* print a,b,c */ +OPCODE(ERR, B) /* raise(LocalJumpError, Lit(a)) */ +OPCODE(EXT1, Z) /* make 1st operand 16bit */ +OPCODE(EXT2, Z) /* make 2nd operand 16bit */ +OPCODE(EXT3, Z) /* make 1st and 2nd operands 16bit */ +OPCODE(STOP, Z) /* stop VM */ diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index 0588dfca5..1b17128fd 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -517,7 +517,7 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value bpno = dbg->method_bpno; dbg->method_bpno = 0; - switch(GET_OPCODE(*pc)) { + switch(*pc) { case OP_SEND: case OP_SENDB: c = mrb_class(mrb, regs[GETARG_A(*pc)]); diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index fec747f0c..3ba2324fb 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -23,6 +23,8 @@ #define MRB_CODEGEN_LEVEL_MAX 1024 #endif +#define MAXARG_S (1<<16) + typedef mrb_ast_node node; typedef struct mrb_parser_state parser_state; @@ -36,7 +38,7 @@ enum looptype { struct loopinfo { enum looptype type; - int pc1, pc2, pc3, acc; + int pc0, pc1, pc2, pc3, acc; int ensure_level; struct loopinfo *prev; }; @@ -50,9 +52,10 @@ typedef struct scope { node *lv; - int sp; - int pc; - int lastlabel; + uint16_t sp; + uint16_t pc; + uint16_t lastpc; + uint16_t lastlabel; int ainfo:15; mrb_bool mscope:1; @@ -63,10 +66,10 @@ typedef struct scope { mrb_code *iseq; uint16_t *lines; - int icapa; + uint32_t icapa; mrb_irep *irep; - int pcapa, scapa, rcapa; + uint32_t pcapa, scapa, rcapa; uint16_t nlocals; uint16_t nregs; @@ -142,38 +145,141 @@ codegen_realloc(codegen_scope *s, void *p, size_t len) static int new_label(codegen_scope *s) { - s->lastlabel = s->pc; - return s->pc; + return s->lastlabel = s->pc; } -static inline int -genop(codegen_scope *s, mrb_code i) +static void +emit_B(codegen_scope *s, uint32_t pc, uint8_t i) { - if (s->pc >= s->icapa) { + if (pc >= s->icapa) { s->icapa *= 2; - if (s->pc >= MAXARG_sBx) { + if (pc >= MAXARG_S) { codegen_error(s, "too big code block"); } - if (s->icapa > MAXARG_sBx) { - s->icapa = MAXARG_sBx; + if (s->icapa > MAXARG_S) { + s->icapa = MAXARG_S; } s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); if (s->lines) { - s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa); + s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa); s->irep->lines = s->lines; } } - s->iseq[s->pc] = i; if (s->lines) { - s->lines[s->pc] = s->lineno; + s->lines[pc] = s->lineno; + } + s->iseq[pc] = i; +} + +static void +emit_S(codegen_scope *s, int pc, uint16_t i) +{ + uint8_t hi = i>>8; + uint8_t lo = i&0xff; + + emit_B(s, pc, hi); + emit_B(s, pc+1, lo); +} + +static void +gen_B(codegen_scope *s, uint8_t i) +{ + emit_B(s, s->pc++, i); +} + +static void +gen_S(codegen_scope *s, uint16_t i) +{ + emit_S(s, s->pc, i); + s->pc += 2; +} + +static void +genop_0(codegen_scope *s, mrb_code i) +{ + s->lastpc = s->pc; + gen_B(s, i); +} + +static void +genop_1(codegen_scope *s, mrb_code i, uint16_t a) +{ + s->lastpc = s->pc; + if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + } + else { + gen_B(s, i); + gen_B(s, (uint8_t)a); + } +} + +static void +genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) +{ + s->lastpc = s->pc; + if (a > 0xff && b > 0xff) { + gen_B(s, OP_EXT3); + gen_B(s, i); + gen_S(s, a); + gen_S(s, b); + } + else if (b > 0xff) { + gen_B(s, OP_EXT2); + gen_B(s, i); + gen_B(s, (uint8_t)a); + gen_S(s, b); + } + else if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + gen_B(s, (uint8_t)b); + } + else { + gen_B(s, i); + gen_B(s, (uint8_t)a); + gen_B(s, (uint8_t)b); } - return s->pc++; +} + +static void +genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint8_t c) +{ + s->lastpc = s->pc; + genop_2(s, i, a, b); + gen_B(s, c); +} + +static void +genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) +{ + s->lastpc = s->pc; + genop_1(s, i, a); + gen_S(s, b); +} + +static void +genop_W(codegen_scope *s, mrb_code i, uint32_t a) +{ + uint8_t a1 = (a>>16) & 0xff; + uint8_t a2 = (a>>8) & 0xff; + uint8_t a3 = a & 0xff; + + s->lastpc = s->pc; + gen_B(s, i); + gen_B(s, a1); + gen_B(s, a2); + gen_B(s, a3); } #define NOVAL 0 #define VAL 1 -static mrb_bool +//static +mrb_bool no_optimize(codegen_scope *s) { if (s && s->parser && s->parser->no_optimize) @@ -181,269 +287,228 @@ no_optimize(codegen_scope *s) return FALSE; } -static int -genop_peep(codegen_scope *s, mrb_code i, int val) +static +mrb_bool +on_eval(codegen_scope *s) { - /* peephole optimization */ - if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) { - mrb_code i0 = s->iseq[s->pc-1]; - int c1 = GET_OPCODE(i); - int c0 = GET_OPCODE(i0); + if (s && s->parser && s->parser->on_eval) + return TRUE; + return FALSE; +} - switch (c1) { - case OP_MOVE: - if (GETARG_A(i) == GETARG_B(i)) { - /* skip useless OP_MOVE */ - return 0; - } - if (val) break; - switch (c0) { - case OP_MOVE: - if (GETARG_A(i) == GETARG_A(i0)) { - /* skip overriden OP_MOVE */ - s->pc--; - s->iseq[s->pc] = i; - } - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) { - /* skip swapping OP_MOVE */ - return 0; - } - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->pc--; - return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val); - } - break; - case OP_LOADI: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0)); - return 0; - } - break; - case OP_ARRAY: - case OP_HASH: - case OP_RANGE: - case OP_AREF: - case OP_GETUPVAR: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0)); - return 0; - } - break; - case OP_LOADSYM: - case OP_GETGLOBAL: - case OP_GETIV: - case OP_GETCV: - case OP_GETCONST: - case OP_GETSPECIAL: - case OP_LOADL: - case OP_STRING: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0)); - return 0; - } - break; - case OP_SCLASS: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0)); - return 0; - } - break; - case OP_LOADNIL: - case OP_LOADSELF: - case OP_LOADT: - case OP_LOADF: - case OP_OCLASS: - if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i)); - return 0; - } - break; - default: - break; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETGLOBAL: - if (val) break; - if (c0 == OP_MOVE) { - if (GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i)); - return 0; - } - } - break; - case OP_SETUPVAR: - if (val) break; - if (c0 == OP_MOVE) { - if (GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i)); - return 0; - } - } - break; - case OP_GETUPVAR: - if (c0 == OP_SETUPVAR) { - if (GETARG_B(i) == GETARG_B(i0) && GETARG_C(i) == GETARG_C(i0)) { - if (GETARG_A(i) == GETARG_A(i0)) { - /* just skip OP_SETUPVAR */ - return 0; - } - else { - return genop(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_A(i0))); - } - } - } - break; - case OP_EPOP: - if (c0 == OP_EPOP) { - s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i)); - return 0; - } - break; - case OP_POPERR: - if (c0 == OP_POPERR) { - s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i)); - return 0; - } - break; - case OP_RETURN: - switch (c0) { - case OP_RETURN: - return 0; - case OP_MOVE: - if (GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL); - return 0; - } - break; - case OP_SETIV: - case OP_SETCV: - case OP_SETCONST: - case OP_SETMCNST: - case OP_SETUPVAR: - case OP_SETGLOBAL: - s->pc--; - genop_peep(s, i0, NOVAL); - i0 = s->iseq[s->pc-1]; - return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL)); -#if 0 - case OP_SEND: - if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0)); - return; - } - break; -#endif - default: - break; - } - break; - case OP_ADD: - case OP_SUB: - if (c0 == OP_LOADI) { - int c = GETARG_sBx(i0); - - if (c1 == OP_SUB) c = -c; - if (c > 127 || c < -127) break; - if (0 <= c) - s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c); - else - s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c); - return 0; - } - break; - case OP_ARYCAT: - case OP_ARYPUSH: - if (c0 == OP_MOVE && GETARG_A(i0) >= s->nlocals) { - s->iseq[s->pc-1] = MKOP_AB(c1, GETARG_A(i), GETARG_B(i0)); - return 0; - } - break; - case OP_STRCAT: - if (c0 == OP_STRING) { - mrb_value v = s->irep->pool[GETARG_Bx(i0)]; +struct mrb_insn_data { + uint8_t insn; + uint16_t a; + uint16_t b; + uint8_t c; +}; - if (mrb_string_p(v) && RSTRING_LEN(v) == 0) { - s->pc--; - return 0; - } - } - if (c0 == OP_LOADNIL) { - if (GETARG_B(i) == GETARG_A(i0)) { - s->pc--; - return 0; - } - } - break; - case OP_JMPIF: - case OP_JMPNOT: - if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) { - s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i)); - return s->pc-1; - } - break; - default: - break; +struct mrb_insn_data +mrb_decode_insn(codegen_scope *s, mrb_code *pc) +{ + struct mrb_insn_data data = { 0 }; + mrb_code insn = READ_B(); + uint16_t a = 0; + uint16_t b = 0; + uint8_t c = 0; + + switch (insn) { +#define FETCH_Z() /* empty */ +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; +#include "mruby/ops.h" +#undef OPCODE + } + switch (insn) { + case OP_EXT1: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT2: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT3: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: + break; + } + data.insn = insn; + data.a = a; + data.b = b; + data.c = c; + return data; +} + +struct mrb_insn_data +mrb_last_insn(codegen_scope *s) +{ + if (s->pc == s->lastpc) { + struct mrb_insn_data data; + + data.insn = OP_NOP; + return data; + } + return mrb_decode_insn(s, &s->iseq[s->lastpc]); +} + +static mrb_bool +no_peephole(codegen_scope *s) +{ + return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; +} + +static uint16_t +genjmp(codegen_scope *s, mrb_code i, uint16_t pc) +{ + uint16_t pos; + + s->lastpc = s->pc; + gen_B(s, i); + pos = s->pc; + gen_S(s, pc); + return pos; +} + +static uint16_t +genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) +{ + uint16_t pos; + + if (!no_peephole(s) && !val) { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_MOVE && data.a == a) { + s->pc = s->lastpc; + a = data.b; } } - return genop(s, i); + + s->lastpc = s->pc; + if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + pos = s->pc; + gen_S(s, pc); + } + else { + gen_B(s, i); + gen_B(s, a); + pos = s->pc; + gen_S(s, pc); + } + return pos; } static void -scope_error(codegen_scope *s) +gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) { - exit(EXIT_FAILURE); + if (no_peephole(s)) { + normal: + genop_2(s, OP_MOVE, dst, src); + return; + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + switch (data.insn) { + case OP_MOVE: + if (dst == src) return; /* remove useless MOVE */ + if (data.b == dst && data.a == src) /* skip swapping MOVE */ + return; + goto normal; + case OP_LOADNIL: case OP_LOADSELF: case OP_LOADT: case OP_LOADF: + case OP_LOADI__1: + case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: + case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: + if (nopeep || data.a != src || data.a < s->nlocals) goto normal; + s->pc = s->lastpc; + genop_1(s, data.insn, dst); + break; + case OP_LOADI: case OP_LOADINEG: case OP_LOADL: case OP_LOADSYM: + case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV: + case OP_GETCONST: case OP_STRING: + case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH: + if (nopeep || data.a != src || data.a < s->nlocals) goto normal; + s->pc = s->lastpc; + genop_2(s, data.insn, dst, data.b); + break; + default: + goto normal; + } + } } static void -distcheck(codegen_scope *s, int diff) +gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) { - if (diff > MAXARG_sBx || diff < -MAXARG_sBx) { - codegen_error(s, "too distant jump address"); + if (no_peephole(s)) { + normal: + genop_2(s, op, dst, idx); + return; + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + switch (data.insn) { + case OP_LOADI__1: + if (op == OP_ADD) op = OP_SUB; + else op = OP_ADD; + data.b = 1; + goto replace; + case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: + case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: + data.b = data.insn - OP_LOADI_0; + /* fall through */ + case OP_LOADI: + replace: + if (data.b >= 128) goto normal; + s->pc = s->lastpc; + if (op == OP_ADD) { + genop_3(s, OP_ADDI, dst, idx, data.b); + } + else { + genop_3(s, OP_SUBI, dst, idx, data.b); + } + break; + default: + goto normal; + } } } -static inline void -dispatch(codegen_scope *s, int pc) +static int +dispatch(codegen_scope *s, uint16_t pos0) { - int diff = s->pc - pc; - mrb_code i = s->iseq[pc]; - int c = GET_OPCODE(i); + uint16_t newpos; s->lastlabel = s->pc; - switch (c) { - case OP_JMP: - case OP_JMPIF: - case OP_JMPNOT: - case OP_ONERR: - break; - default: -#ifndef MRB_DISABLE_STDIO - fprintf(stderr, "bug: dispatch on non JMP op\n"); -#endif - scope_error(s); - break; - } - distcheck(s, diff); - s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff); + newpos = PEEK_S(s->iseq+pos0); + emit_S(s, pos0, s->pc); + return newpos; } static void -dispatch_linked(codegen_scope *s, int pc) +dispatch_linked(codegen_scope *s, uint16_t pos) { - mrb_code i; - int pos; - - if (!pc) return; + if (pos==0) return; for (;;) { - i = s->iseq[pc]; - pos = GETARG_sBx(i); - dispatch(s, pc); - if (!pos) break; - pc = pos; + pos = dispatch(s, pos); + if (pos==0) break; } } @@ -451,7 +516,7 @@ dispatch_linked(codegen_scope *s, int pc) static void push_(codegen_scope *s) { - if (s->sp > 511) { + if (s->sp >= 0xffff) { codegen_error(s, "too complex expression"); } s->sp++; @@ -461,7 +526,7 @@ push_(codegen_scope *s) static void push_n_(codegen_scope *s, int n) { - if (s->sp+n > 511) { + if (s->sp+n >= 0xffff) { codegen_error(s, "too complex expression"); } s->sp+=n; @@ -545,52 +610,23 @@ new_lit(codegen_scope *s, mrb_value val) return i; } -/* method symbols should be fit in 9 bits */ -#define MAXMSYMLEN 512 /* maximum symbol numbers */ -#define MAXSYMLEN 65536 +#define MAXSYMLEN 0x10000 static int -new_msym(codegen_scope *s, mrb_sym sym) +new_sym(codegen_scope *s, mrb_sym sym) { int i, len; mrb_assert(s->irep); len = s->irep->slen; - if (len > MAXMSYMLEN) len = MAXMSYMLEN; for (i=0; iirep->syms[i] == sym) return i; - if (s->irep->syms[i] == 0) break; } - if (i == MAXMSYMLEN) { - codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")"); - } - s->irep->syms[i] = sym; - if (i == s->irep->slen) s->irep->slen++; - return i; -} - -static int -new_sym(codegen_scope *s, mrb_sym sym) -{ - int i; - - for (i=0; iirep->slen; i++) { - if (s->irep->syms[i] == sym) return i; - } - if (s->irep->slen == MAXSYMLEN) { - codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXSYMLEN) ")"); - } - - if (s->irep->slen > MAXMSYMLEN/2 && s->scapa == MAXMSYMLEN) { - s->scapa = MAXSYMLEN; - s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*MAXSYMLEN); - for (i = s->irep->slen; i < MAXMSYMLEN; i++) { - static const mrb_sym mrb_sym_zero = { 0 }; - s->irep->syms[i] = mrb_sym_zero; - } - s->irep->slen = MAXMSYMLEN; + if (s->irep->slen >= s->scapa) { + s->scapa *= 2; + s->irep->syms = (mrb_sym*)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*s->scapa); } s->irep->syms[s->irep->slen] = sym; return s->irep->slen++; @@ -631,7 +667,6 @@ for_body(codegen_scope *s, node *tree) int idx; struct loopinfo *lp; node *n2; - mrb_code c; /* generate receiver */ codegen(s, tree->cdr->car, VAL); @@ -645,7 +680,7 @@ for_body(codegen_scope *s, node *tree) /* generate loop variable */ n2 = tree->car; - genop(s, MKOP_Ax(OP_ENTER, 0x40000)); + genop_W(s, OP_ENTER, 0x40000); if (n2->car && !n2->car->cdr && !n2->cdr) { gen_assignment(s, n2->car->car, 1, NOVAL); } @@ -659,25 +694,20 @@ for_body(codegen_scope *s, node *tree) /* loop body */ codegen(s, tree->cdr->cdr->car, VAL); pop(); - if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } + genop_1(s, OP_RETURN, cursp()); loop_pop(s, NOVAL); scope_finish(s); s = prev; - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK)); + genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1); push();pop(); /* space for a block */ pop(); - idx = new_msym(s, mrb_intern_lit(s->mrb, "each")); - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0)); + idx = new_sym(s, mrb_intern_lit(s->mrb, "each")); + genop_3(s, OP_SENDB, cursp(), idx, 0); } static int lambda_body(codegen_scope *s, node *tree, int blk) { - mrb_code c; codegen_scope *parent = s; s = scope_new(s->mrb, s, tree->car); if (s == NULL) { @@ -688,7 +718,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) if (blk) { struct loopinfo *lp = loop_push(s, LOOP_BLOCK); - lp->pc1 = new_label(s); + lp->pc0 = new_label(s); } tree = tree->cdr; if (tree->car) { @@ -721,45 +751,36 @@ lambda_body(codegen_scope *s, node *tree, int blk) s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ | ((ra & 1) << 5) | (pa & 0x1f); - genop(s, MKOP_Ax(OP_ENTER, a)); + genop_W(s, OP_ENTER, a); pos = new_label(s); for (i=0; i 0) { - genop(s, MKOP_sBx(OP_JMP, 0)); + genjmp(s, OP_JMP, 0); } opt = tree->car->cdr->car; i = 0; while (opt) { int idx; - dispatch(s, pos+i); + dispatch(s, pos+i*3+1); codegen(s, opt->car->cdr, VAL); - idx = lv_idx(s, nsym(opt->car->car)); pop(); - genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL); + idx = lv_idx(s, nsym(opt->car->car)); + gen_move(s, idx, cursp(), 0); i++; opt = opt->cdr; } if (oa > 0) { - dispatch(s, pos+i); + dispatch(s, pos+i*3+1); } } codegen(s, tree->cdr->car, VAL); pop(); if (s->pc > 0) { - c = s->iseq[s->pc-1]; - if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) { - if (s->nregs == 0) { - genop(s, MKOP_A(OP_LOADNIL, 0)); - genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); - } - } + genop_1(s, OP_RETURN, cursp()); } if (blk) { loop_pop(s, NOVAL); @@ -773,24 +794,13 @@ scope_body(codegen_scope *s, node *tree, int val) { codegen_scope *scope = scope_new(s->mrb, s, tree->car); if (scope == NULL) { - raise_error(s, "unexpected scope"); + codegen_error(s, "unexpected scope"); } codegen(scope, tree->cdr, VAL); + genop_1(scope, OP_RETURN, scope->sp-1); if (!s->iseq) { - genop(scope, MKOP_A(OP_STOP, 0)); - } - else if (!val) { - genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - if (scope->nregs == 0) { - genop(scope, MKOP_A(OP_LOADNIL, 0)); - genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL)); - } - else { - genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL); - } + genop_0(scope, OP_STOP); } scope_finish(scope); if (!s->irep) { @@ -854,15 +864,15 @@ gen_values(codegen_scope *s, node *t, int val, int extra) } else { pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + genop_2(s, OP_ARRAY, cursp(), n); push(); codegen(s, t->car, VAL); pop(); pop(); if (is_splat) { - genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYCAT, cursp()); } else { - genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYPUSH, cursp()); } } t = t->cdr; @@ -871,10 +881,10 @@ gen_values(codegen_scope *s, node *t, int val, int extra) codegen(s, t->car, VAL); pop(); pop(); if (nint(t->car->car) == NODE_SPLAT) { - genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYCAT, cursp()); } else { - genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL); + genop_1(s, OP_ARYPUSH, cursp()); } t = t->cdr; } @@ -905,16 +915,10 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) codegen(s, tree->car, VAL); /* receiver */ if (safe) { int recv = cursp()-1; - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); - genop(s, MKOP_AB(OP_MOVE, cursp(), recv)); - push_n(2); pop_n(2); /* space for one arg and a block */ - pop(); - idx = new_msym(s, mrb_intern_lit(s->mrb, "==")); - genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1)); - skip = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + gen_move(s, cursp(), recv, 0); + skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } - idx = new_msym(s, sym); + idx = new_sym(s, sym); tree = tree->cdr->cdr->car; if (tree) { n = gen_values(s, tree->car, VAL, sp?1:0); @@ -923,14 +927,15 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) push(); } } - if (sp) { + if (sp) { /* last argument pushed (attr=) */ if (sendv) { + gen_move(s, cursp(), sp, 0); pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp)); + genop_1(s, OP_ARYPUSH, cursp()); push(); } else { - genop(s, MKOP_AB(OP_MOVE, cursp(), sp)); + gen_move(s, cursp(), sp, 0); push(); n++; } @@ -939,9 +944,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) noop = 1; codegen(s, tree->cdr, VAL); pop(); - } - else { - blk = cursp(); + blk = 1; } push();pop(); pop_n(n+1); @@ -950,39 +953,38 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); if (!noop && symlen == 1 && symname[0] == '+' && n == 1) { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val); + gen_addsub(s, OP_ADD, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val); + gen_addsub(s, OP_SUB, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n)); + genop_2(s, OP_MUL, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n)); + genop_2(s, OP_DIV, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, n)); + genop_2(s, OP_LT, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, n)); + genop_2(s, OP_LE, cursp(), idx); } else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, n)); + genop_2(s, OP_GT, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, n)); + genop_2(s, OP_GE, cursp(), idx); } else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) { - genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n)); + genop_2(s, OP_EQ, cursp(), idx); } else { - if (sendv) n = CALL_MAXARGS; - if (blk > 0) { /* no block */ - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n)); + if (sendv) { + genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx); } else { - genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n)); + genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), idx, n); } } } @@ -1004,13 +1006,14 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) switch (type) { case NODE_GVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val); + genop_2(s, OP_SETGV, sp, idx); break; case NODE_LVAR: idx = lv_idx(s, nsym(tree)); if (idx > 0) { if (idx != sp) { - genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val); + gen_move(s, idx, sp, val); + if (val && on_eval(s)) genop_0(s, OP_NOP); } break; } @@ -1021,7 +1024,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) while (up) { idx = lv_idx(up, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val); + genop_3(s, OP_SETUPVAR, sp, idx, lv); break; } lv++; @@ -1031,23 +1034,23 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) break; case NODE_IVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val); + genop_2(s, OP_SETIV, sp, idx); break; case NODE_CVAR: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val); + genop_2(s, OP_SETCV, sp, idx); break; case NODE_CONST: idx = new_sym(s, nsym(tree)); - genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val); + genop_2(s, OP_SETCONST, sp, idx); break; case NODE_COLON2: - idx = new_sym(s, nsym(tree->cdr)); - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL); + gen_move(s, cursp(), sp, 0); push(); codegen(s, tree->car, VAL); pop_n(2); - genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val); + idx = new_sym(s, nsym(tree->cdr)); + genop_2(s, OP_SETMCNST, sp, idx); break; case NODE_CALL: @@ -1057,7 +1060,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) type == NODE_SCALL); pop(); if (val) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val); + gen_move(s, cursp(), sp, 0); } break; @@ -1090,7 +1093,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) while (t) { int sp = cursp(); - genop(s, MKOP_ABC(OP_AREF, sp, rhs, n)); + genop_3(s, OP_AREF, sp, rhs, n); push(); gen_assignment(s, t->car, sp, NOVAL); pop(); @@ -1107,10 +1110,10 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) p = p->cdr; } } - genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); + gen_move(s, cursp(), rhs, val); push_n(post+1); pop_n(post+1); - genop(s, MKOP_ABC(OP_APOST, cursp(), n, post)); + genop_3(s, OP_APOST, cursp(), n, post); n = 1; if (t->car) { /* rest */ gen_assignment(s, t->car, cursp(), NOVAL); @@ -1124,19 +1127,19 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) } } if (val) { - genop(s, MKOP_AB(OP_MOVE, cursp(), rhs)); + gen_move(s, cursp(), rhs, 0); } } } static void -gen_send_intern(codegen_scope *s) +gen_intern(codegen_scope *s) { - push();pop(); /* space for a block */ pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0)); + genop_1(s, OP_INTERN, cursp()); push(); } + static void gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) { @@ -1159,25 +1162,25 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) j = 0; ++i; if (sym) - gen_send_intern(s); + gen_intern(s); } break; } - if (j >= 2) { + while (j >= 2) { pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); - j = 1; + j--; } tree = tree->cdr; } if (j > 0) { ++i; if (sym) - gen_send_intern(s); + gen_intern(s); } pop_n(i); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i)); + genop_2(s, OP_ARRAY, cursp(), i); push(); } else { @@ -1196,7 +1199,7 @@ raise_error(codegen_scope *s, const char *msg) { int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg)); - genop(s, MKOP_ABx(OP_ERR, 1, idx)); + genop_1(s, OP_ERR, idx); } #ifndef MRB_WITHOUT_FLOAT @@ -1274,11 +1277,9 @@ static void gen_retval(codegen_scope *s, node *tree) { if (nint(tree->car) == NODE_SPLAT) { - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0)); - push(); codegen(s, tree, VAL); - pop(); pop(); - genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1)); + pop(); + genop_1(s, OP_ARYDUP, cursp()); } else { codegen(s, tree, VAL); @@ -1294,7 +1295,7 @@ codegen(codegen_scope *s, node *tree, int val) if (!tree) { if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } return; @@ -1318,7 +1319,7 @@ codegen(codegen_scope *s, node *tree, int val) switch (nt) { case NODE_BEGIN: if (val && !tree) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } while (tree) { @@ -1329,18 +1330,18 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_RESCUE: { - int onerr, noexc, exend, pos1, pos2, tmp; + int noexc, exend, pos1, pos2, tmp; struct loopinfo *lp; if (tree->car == NULL) goto exit; - onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); lp = loop_push(s, LOOP_BEGIN); - lp->pc1 = onerr; + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_ONERR, 0); codegen(s, tree->car, VAL); pop(); lp->type = LOOP_RESCUE; - noexc = genop(s, MKOP_Bx(OP_JMP, 0)); - dispatch(s, onerr); + noexc = genjmp(s, OP_JMP, 0); + dispatch(s, lp->pc1); tree = tree->cdr; exend = 0; pos1 = 0; @@ -1348,7 +1349,7 @@ codegen(codegen_scope *s, node *tree, int val) node *n2 = tree->car; int exc = cursp(); - genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0)); + genop_1(s, OP_EXCEPT, exc); push(); while (n2) { node *n3 = n2->car; @@ -1359,30 +1360,29 @@ codegen(codegen_scope *s, node *tree, int val) do { if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) { codegen(s, n4->car, VAL); - genop(s, MKOP_AB(OP_MOVE, cursp(), exc)); + gen_move(s, cursp(), exc, 0); push_n(2); pop_n(2); /* space for one arg and a block */ pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1); } else { if (n4) { codegen(s, n4->car, VAL); } else { - genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError")))); + genop_2(s, OP_GETCONST, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "StandardError"))); push(); } pop(); - genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1)); + genop_2(s, OP_RESCUE, exc, cursp()); } - distcheck(s, pos2); - tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val); pos2 = tmp; if (n4) { n4 = n4->cdr; } } while (n4); - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos1 = genjmp(s, OP_JMP, 0); dispatch_linked(s, pos2); pop(); @@ -1393,21 +1393,20 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, n3->cdr->cdr->car, val); if (val) pop(); } - distcheck(s, exend); - tmp = genop(s, MKOP_sBx(OP_JMP, exend)); + tmp = genjmp(s, OP_JMP, exend); exend = tmp; n2 = n2->cdr; push(); } if (pos1) { dispatch(s, pos1); - genop(s, MKOP_A(OP_RAISE, exc)); + genop_1(s, OP_RAISE, exc); } } pop(); tree = tree->cdr; dispatch(s, noexc); - genop(s, MKOP_A(OP_POPERR, 1)); + genop_1(s, OP_POPERR, 1); if (tree->car) { codegen(s, tree->car, val); } @@ -1424,15 +1423,13 @@ codegen(codegen_scope *s, node *tree, int val) (nint(tree->cdr->cdr->car) == NODE_BEGIN && tree->cdr->cdr->cdr)) { int idx; - int epush = s->pc; - genop(s, MKOP_Bx(OP_EPUSH, 0)); s->ensure_level++; - codegen(s, tree->car, val); idx = scope_body(s, tree->cdr, NOVAL); - s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx); + genop_1(s, OP_EPUSH, idx); + codegen(s, tree->car, val); s->ensure_level--; - genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL); + genop_1(s, OP_EPOP, 1); } else { /* empty ensure ignored */ codegen(s, tree->car, val); @@ -1443,7 +1440,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int idx = lambda_body(s, tree, 1); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA)); + genop_2(s, OP_LAMBDA, cursp(), idx); push(); } break; @@ -1452,7 +1449,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int idx = lambda_body(s, tree, 1); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK)); + genop_2(s, OP_BLOCK, cursp(), idx); push(); } break; @@ -1460,10 +1457,10 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_IF: { int pos1, pos2; - node *e = tree->cdr->cdr->car; + node *elsepart = tree->cdr->cdr->car; if (!tree->car) { - codegen(s, e, val); + codegen(s, elsepart, val); goto exit; } switch (nint(tree->car->car)) { @@ -1474,27 +1471,27 @@ codegen(codegen_scope *s, node *tree, int val) goto exit; case NODE_FALSE: case NODE_NIL: - codegen(s, e, val); + codegen(s, elsepart, val); goto exit; } codegen(s, tree->car, VAL); pop(); - pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL); + pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val); codegen(s, tree->cdr->car, val); - if (e) { + if (elsepart) { if (val) pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos2 = genjmp(s, OP_JMP, 0); dispatch(s, pos1); - codegen(s, e, val); + codegen(s, elsepart, val); dispatch(s, pos2); } else { if (val) { pop(); - pos2 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos2 = genjmp(s, OP_JMP, 0); dispatch(s, pos1); - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); dispatch(s, pos2); push(); } @@ -1511,7 +1508,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0)); + pos = genjmp2(s, OP_JMPNOT, cursp(), 0, val); codegen(s, tree->cdr, val); dispatch(s, pos); } @@ -1523,7 +1520,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0)); + pos = genjmp2(s, OP_JMPIF, cursp(), 0, val); codegen(s, tree->cdr, val); dispatch(s, pos); } @@ -1533,14 +1530,14 @@ codegen(codegen_scope *s, node *tree, int val) { struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_JMP, 0); lp->pc2 = new_label(s); codegen(s, tree->cdr, NOVAL); dispatch(s, lp->pc1); codegen(s, tree->car, VAL); pop(); - distcheck(s, lp->pc2 - s->pc); - genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc)); + genjmp2(s, OP_JMPIF, cursp(), lp->pc2, NOVAL); loop_pop(s, val); } @@ -1550,14 +1547,14 @@ codegen(codegen_scope *s, node *tree, int val) { struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0)); + lp->pc0 = new_label(s); + lp->pc1 = genjmp(s, OP_JMP, 0); lp->pc2 = new_label(s); codegen(s, tree->cdr, NOVAL); dispatch(s, lp->pc1); codegen(s, tree->car, VAL); pop(); - distcheck(s, lp->pc2 - s->pc); - genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc)); + genjmp2(s, OP_JMPNOT, cursp(), lp->pc2, NOVAL); loop_pop(s, val); } @@ -1586,43 +1583,40 @@ codegen(codegen_scope *s, node *tree, int val) while (n) { codegen(s, n->car, VAL); if (head) { - genop(s, MKOP_AB(OP_MOVE, cursp(), head)); - push_n(2); pop_n(2); /* space for one arg and a block */ - pop(); + gen_move(s, cursp(), head, 0); + push(); push(); pop(); pop(); pop(); if (nint(n->car->car) == NODE_SPLAT) { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1); } else { - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "===")), 1); } } else { pop(); } - distcheck(s, pos2); - tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2)); + tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, NOVAL); pos2 = tmp; n = n->cdr; } if (tree->car->car) { - pos1 = genop(s, MKOP_sBx(OP_JMP, 0)); + pos1 = genjmp(s, OP_JMP, 0); dispatch_linked(s, pos2); } codegen(s, tree->car->cdr, val); if (val) pop(); - distcheck(s, pos3); - tmp = genop(s, MKOP_sBx(OP_JMP, pos3)); + tmp = genjmp(s, OP_JMP, pos3); pos3 = tmp; if (pos1) dispatch(s, pos1); tree = tree->cdr; } if (val) { int pos = cursp(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); if (pos3) dispatch_linked(s, pos3); if (head) pop(); if (cursp() != pos) { - genop(s, MKOP_AB(OP_MOVE, cursp(), pos)); + gen_move(s, cursp(), pos, 0); } push(); } @@ -1654,7 +1648,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr, val); if (val) { pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE)); + genop_1(s, OP_RANGE_INC, cursp()); push(); } break; @@ -1664,7 +1658,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr, val); if (val) { pop(); pop(); - genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE)); + genop_1(s, OP_RANGE_EXC, cursp()); push(); } break; @@ -1675,7 +1669,7 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_2(s, OP_GETMCNST, cursp(), sym); if (val) push(); } break; @@ -1684,8 +1678,8 @@ codegen(codegen_scope *s, node *tree, int val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); if (val) push(); } break; @@ -1698,7 +1692,7 @@ codegen(codegen_scope *s, node *tree, int val) if (n >= 0) { if (val) { pop_n(n); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n)); + genop_2(s, OP_ARRAY, cursp(), n); push(); } } @@ -1718,12 +1712,14 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car->cdr, val); len++; tree = tree->cdr; - if (val && len == 126) { + if (val && len == 255) { pop_n(len*2); - genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); - if (update) { + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + genop_2(s, OP_HASHADD, cursp(), len); } push(); update = TRUE; @@ -1732,10 +1728,12 @@ codegen(codegen_scope *s, node *tree, int val) } if (val) { pop_n(len*2); - genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len)); - if (update) { + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { pop(); - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1)); + genop_2(s, OP_HASHADD, cursp(), len); } push(); } @@ -1776,7 +1774,7 @@ codegen(codegen_scope *s, node *tree, int val) n++; } else { - genop(s, MKOP_A(OP_LOADNIL, rhs+n)); + genop_1(s, OP_LOADNIL, rhs+n); gen_assignment(s, t->car, rhs+n, NOVAL); } t = t->cdr; @@ -1800,7 +1798,7 @@ codegen(codegen_scope *s, node *tree, int val) else { rn = len - post - n; } - genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn)); + genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn); gen_assignment(s, t->car, cursp(), NOVAL); n += rn; } @@ -1815,7 +1813,7 @@ codegen(codegen_scope *s, node *tree, int val) } pop_n(len); if (val) { - genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len)); + genop_2(s, OP_ARRAY, rhs, len); push(); } } @@ -1843,17 +1841,17 @@ codegen(codegen_scope *s, node *tree, int val) int onerr, noexc, exc; struct loopinfo *lp; - onerr = genop(s, MKOP_Bx(OP_ONERR, 0)); + onerr = genjmp(s, OP_ONERR, 0); lp = loop_push(s, LOOP_BEGIN); lp->pc1 = onerr; exc = cursp(); codegen(s, tree->car, VAL); lp->type = LOOP_RESCUE; - genop(s, MKOP_A(OP_POPERR, 1)); - noexc = genop(s, MKOP_Bx(OP_JMP, 0)); + genop_1(s, OP_POPERR, 1); + noexc = genjmp(s, OP_JMP, 0); dispatch(s, onerr); - genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0)); - genop(s, MKOP_A(OP_LOADF, exc)); + genop_1(s, OP_EXCEPT, exc); + genop_1(s, OP_LOADF, exc); dispatch(s, noexc); loop_pop(s, NOVAL); } @@ -1867,7 +1865,7 @@ codegen(codegen_scope *s, node *tree, int val) push(); } codegen(s, n->car, VAL); /* receiver */ - idx = new_msym(s, nsym(n->cdr->car)); + idx = new_sym(s, nsym(n->cdr->car)); base = cursp()-1; if (n->cdr->cdr->car) { nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1); @@ -1881,12 +1879,12 @@ codegen(codegen_scope *s, node *tree, int val) } } /* copy receiver and arguments */ - genop(s, MKOP_AB(OP_MOVE, cursp(), base)); + gen_move(s, cursp(), base, 0); for (i=0; i= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } - pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0)); + pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val); } else { - pos = genop_peep(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0), NOVAL); + pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val); } codegen(s, tree->cdr->cdr->car, VAL); pop(); if (val && vsp >= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } if (nint(tree->car->car) == NODE_CALL) { if (callargs == CALL_MAXARGS) { pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + genop_1(s, OP_ARYPUSH, cursp()); } else { pop_n(callargs); callargs++; } pop(); - idx = new_msym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car))); + genop_3(s, OP_SEND, cursp(), idx, callargs); } else { gen_assignment(s, tree->car, cursp(), val); @@ -1935,52 +1933,52 @@ codegen(codegen_scope *s, node *tree, int val) push(); pop(); pop(); pop(); - idx = new_msym(s, sym); + idx = new_sym(s, sym); if (len == 1 && name[0] == '+') { - genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val); + gen_addsub(s, OP_ADD, cursp(), idx); } else if (len == 1 && name[0] == '-') { - genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val); + gen_addsub(s, OP_SUB, cursp(), idx); } else if (len == 1 && name[0] == '*') { - genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1)); + genop_2(s, OP_MUL, cursp(), idx); } else if (len == 1 && name[0] == '/') { - genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1)); + genop_2(s, OP_DIV, cursp(), idx); } else if (len == 1 && name[0] == '<') { - genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1)); + genop_2(s, OP_LT, cursp(), idx); } else if (len == 2 && name[0] == '<' && name[1] == '=') { - genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1)); + genop_2(s, OP_LE, cursp(), idx); } else if (len == 1 && name[0] == '>') { - genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1)); + genop_2(s, OP_GT, cursp(), idx); } else if (len == 2 && name[0] == '>' && name[1] == '=') { - genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1)); + genop_2(s, OP_GE, cursp(), idx); } else { - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1)); + genop_3(s, OP_SEND, cursp(), idx, 1); } if (callargs < 0) { gen_assignment(s, tree->car, cursp(), val); } else { if (val && vsp >= 0) { - genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); + gen_move(s, vsp, cursp(), 0); } if (callargs == CALL_MAXARGS) { pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); + genop_1(s, OP_ARYPUSH, cursp()); } else { pop_n(callargs); callargs++; } pop(); - idx = new_msym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); - genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs)); + idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car))); + genop_3(s, OP_SEND, cursp(), idx, callargs); } } break; @@ -1997,7 +1995,7 @@ codegen(codegen_scope *s, node *tree, int val) s2 = s2->prev; if (!s2) break; } - genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf))); + genop_2S(s, OP_ARGARY, cursp(), (lv & 0xf)); push(); push(); /* ARGARY pushes two values */ pop(); pop(); if (tree) { @@ -2015,12 +2013,12 @@ codegen(codegen_scope *s, node *tree, int val) pop(); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); pop(); } pop_n(n+1); if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n)); + genop_2(s, OP_SUPER, cursp(), n); if (val) push(); } break; @@ -2037,14 +2035,14 @@ codegen(codegen_scope *s, node *tree, int val) if (!s2) break; } if (s2) ainfo = s2->ainfo; - genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf))); + genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)); push(); push(); pop(); /* ARGARY pushes two values */ if (tree && tree->cdr) { codegen(s, tree->cdr, VAL); pop(); } pop(); pop(); - genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS)); + genop_2(s, OP_SUPER, cursp(), CALL_MAXARGS); if (val) push(); } break; @@ -2054,13 +2052,13 @@ codegen(codegen_scope *s, node *tree, int val) gen_retval(s, tree); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } if (s->loop) { - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN)); + genop_1(s, OP_RETURN_BLK, cursp()); } else { - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + genop_1(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2087,9 +2085,9 @@ codegen(codegen_scope *s, node *tree, int val) } push();pop(); /* space for a block */ pop_n(n+1); - genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf))); + genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)); if (sendv) n = CALL_MAXARGS; - genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n)); + genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "call")), n); if (val) push(); } break; @@ -2105,11 +2103,10 @@ codegen(codegen_scope *s, node *tree, int val) } else if (s->loop->type == LOOP_NORMAL) { if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } codegen(s, tree, NOVAL); - distcheck(s, s->loop->pc1 - s->pc); - genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc)); + genjmp(s, OP_JMP, s->loop->pc0); } else { if (tree) { @@ -2117,9 +2114,9 @@ codegen(codegen_scope *s, node *tree, int val) pop(); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } - genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL); + genop_1(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2130,10 +2127,9 @@ codegen(codegen_scope *s, node *tree, int val) } else { if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } - distcheck(s, s->loop->pc2 - s->pc); - genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc)); + genjmp(s, OP_JMP, s->loop->pc2); } if (val) push(); break; @@ -2160,13 +2156,12 @@ codegen(codegen_scope *s, node *tree, int val) } else { if (n > 0) { - genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL); + genop_1(s, OP_POPERR, n); } if (s->ensure_level > lp->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - lp->ensure_level); } - distcheck(s, s->loop->pc1 - s->pc); - genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc)); + genjmp(s, OP_JMP, lp->pc0); } } if (val) push(); @@ -2178,7 +2173,8 @@ codegen(codegen_scope *s, node *tree, int val) int idx = lv_idx(s, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL); + gen_move(s, cursp(), idx, val); + if (val && on_eval(s)) genop_0(s, OP_NOP); } else { int lv = 0; @@ -2187,7 +2183,7 @@ codegen(codegen_scope *s, node *tree, int val) while (up) { idx = lv_idx(up, nsym(tree)); if (idx > 0) { - genop_peep(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv), VAL); + genop_3(s, OP_GETUPVAR, cursp(), idx, lv); break; } lv++; @@ -2199,29 +2195,29 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_GVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); - push(); + genop_2(s, OP_GETGV, cursp(), sym); + if (val) push(); } break; case NODE_IVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETIV, cursp(), sym)); - push(); + genop_2(s, OP_GETIV, cursp(), sym); + if (val) push(); } break; case NODE_CVAR: - if (val) { + { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETCV, cursp(), sym)); - push(); + genop_2(s, OP_GETCV, cursp(), sym); + if (val) push(); } break; @@ -2229,15 +2225,13 @@ codegen(codegen_scope *s, node *tree, int val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym)); - if (val) { - push(); - } + genop_2(s, OP_GETCONST, cursp(), sym); + if (val) push(); } break; case NODE_DEFINED: - codegen(s, tree, VAL); + codegen(s, tree, val); break; case NODE_BACK_REF: @@ -2249,7 +2243,7 @@ codegen(codegen_scope *s, node *tree, int val) buf[1] = nchar(tree); buf[2] = 0; sym = new_sym(s, mrb_intern_cstr(s->mrb, buf)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + genop_2(s, OP_GETGV, cursp(), sym); push(); } break; @@ -2262,7 +2256,7 @@ codegen(codegen_scope *s, node *tree, int val) str = mrb_format(mrb, "$%S", mrb_fixnum_value(nint(tree))); sym = new_sym(s, mrb_intern_str(mrb, str)); - genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym)); + genop_2(s, OP_GETGV, cursp(), sym); push(); } break; @@ -2272,7 +2266,7 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_BLOCK_ARG: - codegen(s, tree, VAL); + codegen(s, tree, val); break; case NODE_INT: @@ -2280,7 +2274,6 @@ codegen(codegen_scope *s, node *tree, int val) char *p = (char*)tree->car; int base = nint(tree->cdr->car); mrb_int i; - mrb_code co; mrb_bool overflow; i = readint_mrb_int(s, p, base, FALSE, &overflow); @@ -2289,19 +2282,19 @@ codegen(codegen_scope *s, node *tree, int val) double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(s->mrb, f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); } else #endif { - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); - } + if (i == -1) genop_1(s, OP_LOADI__1, cursp()); + else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), -i); + else if (i < 8) genop_1(s, OP_LOADI_0 + i, cursp()); + else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), i); else { int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); } - genop(s, co); } push(); } @@ -2314,7 +2307,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); push(); } break; @@ -2332,7 +2325,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, -f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); push(); } break; @@ -2343,7 +2336,6 @@ codegen(codegen_scope *s, node *tree, int val) char *p = (char*)tree->car; int base = nint(tree->cdr->car); mrb_int i; - mrb_code co; mrb_bool overflow; i = readint_mrb_int(s, p, base, TRUE, &overflow); @@ -2352,18 +2344,18 @@ codegen(codegen_scope *s, node *tree, int val) double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(s->mrb, -f)); - genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); + genop_2(s, OP_LOADL, cursp(), off); } else { #endif - if (i < MAXARG_sBx && i > -MAXARG_sBx) { - co = MKOP_AsBx(OP_LOADI, cursp(), i); + if (i == -1) genop_1(s, OP_LOADI__1, cursp()); + else if (i >= -0xffff) { + genop_2(s, OP_LOADINEG, cursp(), -i); } else { int off = new_lit(s, mrb_fixnum_value(i)); - co = MKOP_ABx(OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); } - genop(s, co); #ifndef MRB_WITHOUT_FLOAT } #endif @@ -2373,13 +2365,13 @@ codegen(codegen_scope *s, node *tree, int val) default: if (val) { - int sym = new_msym(s, mrb_intern_lit(s->mrb, "-")); + int sym = new_sym(s, mrb_intern_lit(s->mrb, "-")); - genop(s, MKOP_ABx(OP_LOADI, cursp(), 0)); + genop_1(s, OP_LOADI_0, cursp()); push(); codegen(s, tree, VAL); pop(); pop(); - genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2)); + genop_2(s, OP_SUB, cursp(), sym); } else { codegen(s, tree, NOVAL); @@ -2397,7 +2389,7 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new(s->mrb, p, len)); mrb_gc_arena_restore(s->mrb, ai); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); } break; @@ -2410,7 +2402,7 @@ codegen(codegen_scope *s, node *tree, int val) node *n = tree; if (!n) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); break; } @@ -2419,7 +2411,7 @@ codegen(codegen_scope *s, node *tree, int val) while (n) { codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } @@ -2450,7 +2442,7 @@ codegen(codegen_scope *s, node *tree, int val) int ai = mrb_gc_arena_save(s->mrb); int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel")); - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); codegen(s, tree->car, VAL); n = tree->cdr; @@ -2461,14 +2453,14 @@ codegen(codegen_scope *s, node *tree, int val) } codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } push(); /* for block */ pop_n(3); sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + genop_3(s, OP_SEND, cursp(), sym, 1); if (val) push(); mrb_gc_arena_restore(s->mrb, ai); } @@ -2482,13 +2474,13 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new(s->mrb, p, len)); int sym; - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); push(); pop_n(3); sym = new_sym(s, mrb_intern_lit(s->mrb, "`")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1)); + genop_3(s, OP_SEND, cursp(), sym, 1); if (val) push(); mrb_gc_arena_restore(s->mrb, ai); } @@ -2504,24 +2496,24 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1)); int argc = 1; - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); push(); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); if (p2 || p3) { if (p2) { /* opt */ off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } push(); argc++; if (p3) { /* enc */ off = new_lit(s, mrb_str_new(s->mrb, p3, 1)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } @@ -2529,7 +2521,7 @@ codegen(codegen_scope *s, node *tree, int val) push(); /* space for a block */ pop_n(argc+2); sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + genop_3(s, OP_SEND, cursp(), sym, argc); mrb_gc_arena_restore(s->mrb, ai); push(); } @@ -2544,15 +2536,15 @@ codegen(codegen_scope *s, node *tree, int val) int off; char *p; - genop(s, MKOP_A(OP_OCLASS, cursp())); - genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym)); + genop_1(s, OP_OCLASS, cursp()); + genop_2(s, OP_GETMCNST, cursp(), sym); push(); codegen(s, n->car, VAL); n = n->cdr; while (n) { codegen(s, n->car, VAL); pop(); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); n = n->cdr; } @@ -2561,29 +2553,29 @@ codegen(codegen_scope *s, node *tree, int val) p = (char*)n->car; off = new_lit(s, mrb_str_new_cstr(s->mrb, p)); codegen(s, tree->car, VAL); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); pop(); - genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL); + genop_1(s, OP_STRCAT, cursp()); push(); } if (n->cdr->car) { /* opt */ char *p2 = (char*)n->cdr->car; off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } if (n->cdr->cdr) { /* enc */ char *p2 = (char*)n->cdr->cdr; off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop(s, MKOP_ABx(OP_STRING, cursp(), off)); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } push(); /* space for a block */ pop_n(argc+2); sym = new_sym(s, mrb_intern_lit(s->mrb, "compile")); - genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc)); + genop_3(s, OP_SEND, cursp(), sym, argc); mrb_gc_arena_restore(s->mrb, ai); push(); } @@ -2603,7 +2595,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int sym = new_sym(s, nsym(tree)); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } break; @@ -2611,55 +2603,46 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_DSYM: codegen(s, tree, val); if (val) { - gen_send_intern(s); + gen_intern(s); } break; case NODE_SELF: if (val) { - genop(s, MKOP_A(OP_LOADSELF, cursp())); + genop_1(s, OP_LOADSELF, cursp()); push(); } break; case NODE_NIL: if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } break; case NODE_TRUE: if (val) { - genop(s, MKOP_A(OP_LOADT, cursp())); + genop_1(s, OP_LOADT, cursp()); push(); } break; case NODE_FALSE: if (val) { - genop(s, MKOP_A(OP_LOADF, cursp())); + genop_1(s, OP_LOADF, cursp()); push(); } break; case NODE_ALIAS: { - int a = new_msym(s, nsym(tree->car)); - int b = new_msym(s, nsym(tree->cdr)); - int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method")); + int a = new_sym(s, nsym(tree->car)); + int b = new_sym(s, nsym(tree->cdr)); - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a)); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b)); - push(); - genop(s, MKOP_A(OP_LOADNIL, cursp())); - push(); /* space for a block */ - pop_n(4); - genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2)); + genop_2(s, OP_ALIAS, a, b); if (val) { + genop_1(s, OP_LOADNIL, cursp()); push(); } } @@ -2667,41 +2650,15 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_UNDEF: { - int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method")); - int num = 0; node *t = tree; - genop(s, MKOP_A(OP_TCLASS, cursp())); - push(); while (t) { - int symbol; - if (num >= CALL_MAXARGS - 1) { - pop_n(num); - genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num)); - while (t) { - symbol = new_msym(s, nsym(t->car)); - push(); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); - pop(); - genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1)); - t = t->cdr; - } - num = CALL_MAXARGS; - break; - } - symbol = new_msym(s, nsym(t->car)); - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol)); - push(); + int symbol = new_sym(s, nsym(t->car)); + genop_1(s, OP_UNDEF, symbol); t = t->cdr; - num++; - } - push();pop(); /* space for a block */ - pop(); - if (num < CALL_MAXARGS) { - pop_n(num); } - genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num)); if (val) { + genop_1(s, OP_LOADNIL, cursp()); push(); } } @@ -2710,13 +2667,14 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_CLASS: { int idx; + node *body; if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); + genop_1(s, OP_OCLASS, cursp()); push(); } else { @@ -2726,14 +2684,17 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->cdr->car, VAL); } else { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } pop(); pop(); - idx = new_msym(s, nsym(tree->car->cdr)); - genop(s, MKOP_AB(OP_CLASS, cursp(), idx)); - idx = scope_body(s, tree->cdr->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + idx = new_sym(s, nsym(tree->car->cdr)); + genop_2(s, OP_CLASS, cursp(), idx); + body = tree->cdr->cdr->car; + if (!(nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL)) { + idx = scope_body(s, body, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2745,21 +2706,24 @@ codegen(codegen_scope *s, node *tree, int val) int idx; if (tree->car->car == (node*)0) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); push(); } else if (tree->car->car == (node*)1) { - genop(s, MKOP_A(OP_OCLASS, cursp())); + genop_1(s, OP_OCLASS, cursp()); push(); } else { codegen(s, tree->car->car, VAL); } pop(); - idx = new_msym(s, nsym(tree->car->cdr)); - genop(s, MKOP_AB(OP_MODULE, cursp(), idx)); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + idx = new_sym(s, nsym(tree->car->cdr)); + genop_2(s, OP_MODULE, cursp(), idx); + if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN && + tree->cdr->car->cdr->cdr == NULL)) { + idx = scope_body(s, tree->cdr->car, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2772,9 +2736,12 @@ codegen(codegen_scope *s, node *tree, int val) codegen(s, tree->car, VAL); pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); - idx = scope_body(s, tree->cdr->car, val); - genop(s, MKOP_ABx(OP_EXEC, cursp(), idx)); + genop_1(s, OP_SCLASS, cursp()); + if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN && + tree->cdr->car->cdr->cdr == NULL)) { + idx = scope_body(s, tree->cdr->car, val); + genop_2(s, OP_EXEC, cursp(), idx); + } if (val) { push(); } @@ -2783,17 +2750,17 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_DEF: { - int sym = new_msym(s, nsym(tree->car)); + int sym = new_sym(s, nsym(tree->car)); int idx = lambda_body(s, tree->cdr, 0); - genop(s, MKOP_A(OP_TCLASS, cursp())); + genop_1(s, OP_TCLASS, cursp()); push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + genop_2(s, OP_METHOD, cursp(), idx); push(); pop(); pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + genop_2(s, OP_DEF, cursp(), sym); if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } } @@ -2802,18 +2769,18 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_SDEF: { node *recv = tree->car; - int sym = new_msym(s, nsym(tree->cdr->car)); + int sym = new_sym(s, nsym(tree->cdr->car)); int idx = lambda_body(s, tree->cdr->cdr, 0); codegen(s, recv, VAL); pop(); - genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp())); + genop_1(s, OP_SCLASS, cursp()); push(); - genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD)); + genop_2(s, OP_METHOD, cursp(), idx); pop(); - genop(s, MKOP_AB(OP_METHOD, cursp(), sym)); + genop_2(s, OP_DEF, cursp(), sym); if (val) { - genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym)); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } } @@ -2875,7 +2842,7 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa); p->irep->plen = 0; - p->scapa = MAXMSYMLEN; + p->scapa = 256; p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa); p->irep->slen = 0; @@ -2971,7 +2938,7 @@ loop_push(codegen_scope *s, enum looptype t) struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo)); p->type = t; - p->pc1 = p->pc2 = p->pc3 = 0; + p->pc0 = p->pc1 = p->pc2 = p->pc3 = 0; p->prev = s->loop; p->ensure_level = s->ensure_level; p->acc = cursp(); @@ -3013,27 +2980,26 @@ loop_break(codegen_scope *s, node *tree) return; } if (n > 0) { - genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL); + genop_1(s, OP_POPERR, n); } if (loop->type == LOOP_NORMAL) { int tmp; if (s->ensure_level > s->loop->ensure_level) { - genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL); + genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); } if (tree) { - genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL); + gen_move(s, loop->acc, cursp(), 0); } - distcheck(s, s->loop->pc3); - tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3)); + tmp = genjmp(s, OP_JMP, loop->pc3); loop->pc3 = tmp; } else { if (!tree) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } - genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK)); + genop_1(s, OP_BREAK, cursp()); } } } @@ -3042,7 +3008,7 @@ static void loop_pop(codegen_scope *s, int val) { if (val) { - genop(s, MKOP_A(OP_LOADNIL, cursp())); + genop_1(s, OP_LOADNIL, cursp()); } dispatch_linked(s, s->loop->pc3); s->loop = s->loop->prev; @@ -3107,3 +3073,56 @@ mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) mrb_irep_remove_lv(mrb, irep->reps[i]); } } + +#undef OPCODE +#define Z 1 +#define S 3 +#define W 4 +/* instruction sizes */ +uint8_t mrb_insn_size[] = { +#define B 2 +#define BB 3 +#define BBB 4 +#define BS 4 +#define SB 4 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef B +#undef BB +#undef BS +#undef SB +#undef BBB +}; +/* EXT1 instruction sizes */ +uint8_t mrb_insn_size1[] = { +#define B 3 +#define BB 4 +#define BBB 5 +#define BS 5 +#define SB 5 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef B +}; +/* EXT2 instruction sizes */ +uint8_t mrb_insn_size2[] = { +#define B 2 +#define OPCODE(_,x) x, +#include "mruby/ops.h" +#undef OPCODE +#undef BB +#undef BBB +#undef BS +#undef SB +}; +/* EXT3 instruction sizes */ +#define BB 5 +#define BBB 6 +#define BS 4 +#define SB 5 +uint8_t mrb_insn_size3[] = { +#define OPCODE(_,x) x, +#include "mruby/ops.h" +}; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 7f848b4df..61d94edc9 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -5534,6 +5534,7 @@ parser_init_cxt(parser_state *p, mrbc_context *cxt) } p->capture_errors = cxt->capture_errors; p->no_optimize = cxt->no_optimize; + p->on_eval = cxt->on_eval; if (cxt->partial_hook) { p->cxt = cxt; } @@ -6648,6 +6649,20 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); break; + case NODE_LITERAL_DELIM: + printf("NODE_LITERAL_DELIM\n"); + break; + + case NODE_SYMBOLS: + printf("NODE_SYMBOLS:\n"); + dump_recur(mrb, tree, offset+1); + break; + + case NODE_WORDS: + printf("NODE_SYMBOLS:\n"); + dump_recur(mrb, tree, offset+1); + break; + default: printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype); break; diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 5c8e78acd..42a4183b7 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -44,7 +44,7 @@ search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom) return NULL; } -static inline mrb_code +static uint16_t search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) { mrb_irep *virep; @@ -57,7 +57,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) } for (pos = 0; pos < virep->nlocals - 1; pos++) { if (vsym == virep->lv[pos].name) { - return (MKARG_B(pos + 1) | MKARG_C(level + bnest)); + return (pos+1)<<8 | (level+bnest); } } } @@ -71,8 +71,8 @@ irep_argc(mrb_irep *irep) mrb_code c; c = irep->iseq[0]; - if (GET_OPCODE(c) == OP_ENTER) { - mrb_aspec ax = GETARG_Ax(c); + if (c == OP_ENTER) { + mrb_aspec ax = PEEK_W(irep->iseq+1); /* extra 1 means a slot for block */ return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1; } @@ -88,95 +88,132 @@ potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals) return TRUE; } +extern uint8_t mrb_insn_size[]; +extern uint8_t mrb_insn_size1[]; +extern uint8_t mrb_insn_size2[]; +extern uint8_t mrb_insn_size3[]; + static void patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) { int i; - mrb_code c; + uint32_t a; + uint16_t b; + uint8_t c; + mrb_code insn; int argc = irep_argc(irep); - for (i = 0; i < irep->ilen; i++) { - c = irep->iseq[i]; - switch(GET_OPCODE(c)){ + for (i = 0; i < irep->ilen; ) { + insn = irep->iseq[i]; + switch(insn){ case OP_EPUSH: - patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top); + b = PEEK_S(irep->iseq+i+1); + patch_irep(mrb, irep->reps[b], bnest + 1, top); break; case OP_LAMBDA: - { - int arg_c = GETARG_c(c); - if (arg_c & OP_L_CAPTURE) { - patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top); - } - } + case OP_BLOCK: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + patch_irep(mrb, irep->reps[b], bnest + 1, top); break; case OP_SEND: - if (GETARG_C(c) != 0) { + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); + if (c != 0) { break; } else { - mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest); + uint16_t arg = search_variable(mrb, irep->syms[b], bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } break; case OP_MOVE: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); /* src part */ - if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) { - mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest); + if (potential_upvar_p(irep->lv, b, argc, irep->nlocals)) { + uint16_t arg = search_variable(mrb, irep->lv[b - 1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = insn = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } /* dst part */ - if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) { - mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest); + if (potential_upvar_p(irep->lv, a, argc, irep->nlocals)) { + uint16_t arg = search_variable(mrb, irep->lv[a - 1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg; + irep->iseq[i] = insn = OP_SETUPVAR; + irep->iseq[i+1] = b; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } break; case OP_GETUPVAR: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); { - int lev = GETARG_C(c)+1; + int lev = c+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); - if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { - mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); + if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { + mrb_code arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_GETUPVAR; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } } break; case OP_SETUPVAR: + a = PEEK_B(irep->iseq+i+1); + b = PEEK_B(irep->iseq+i+2); + c = PEEK_B(irep->iseq+i+3); { - int lev = GETARG_C(c)+1; + int lev = c+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); - if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { - mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); + if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { + mrb_code arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ - irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg; + irep->iseq[i] = OP_SETUPVAR; + irep->iseq[i+1] = a; + irep->iseq[i+2] = arg >> 8; + irep->iseq[i+3] = arg & 0xff; } } } break; - case OP_STOP: - if (mrb->c->ci->acc >= 0) { - irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL); - } - break; + case OP_EXT1: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size1[insn]; + continue; + case OP_EXT2: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size2[insn]; + continue; + case OP_EXT3: + insn = PEEK_B(irep->iseq+1); + i += mrb_insn_size3[insn]; + continue; } + i+=mrb_insn_size[insn]; } } @@ -203,6 +240,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, mrbc_filename(mrb, cxt, file ? file : "(eval)"); cxt->capture_errors = TRUE; cxt->no_optimize = TRUE; + cxt->on_eval = TRUE; p = mrb_parse_nstring(mrb, s, len, cxt); diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index e445b34c8..600567cac 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -387,7 +387,7 @@ mrb_mruby_method_gem_init(mrb_state* mrb) mrb_define_method(mrb, unbound_method, "bind", unbound_method_bind, MRB_ARGS_REQ(1)); mrb_define_method(mrb, unbound_method, "super_method", method_super_method, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "==", method_eql, MRB_ARGS_REQ(1)); - mrb_alias_method(mrb, unbound_method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "==")); + mrb_define_alias(mrb, unbound_method, "eql?", "=="); mrb_define_method(mrb, unbound_method, "to_s", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "inspect", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE()); @@ -396,11 +396,11 @@ mrb_mruby_method_gem_init(mrb_state* mrb) mrb_undef_class_method(mrb, method, "new"); mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1)); - mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "==")); + mrb_define_alias(mrb, method, "eql?", "=="); mrb_define_method(mrb, method, "to_s", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "inspect", method_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "call", method_call, MRB_ARGS_ANY()); - mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "[]"), mrb_intern_lit(mrb, "call")); + mrb_define_alias(mrb, method, "[]", "call"); mrb_define_method(mrb, method, "unbind", method_unbind, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "super_method", method_super_method, MRB_ARGS_NONE()); mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index b13606f5f..323529dcc 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -109,6 +109,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) mrb_aspec aspec; mrb_value sname, parameters; int i, j; + int max = -1; if (MRB_PROC_CFUNC_P(proc)) { // TODO cfunc aspec is not implemented yet @@ -120,7 +121,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) if (!irep->lv) { return mrb_ary_new(mrb); } - if (GET_OPCODE(*irep->iseq) != OP_ENTER) { + if (*irep->iseq != OP_ENTER) { return mrb_ary_new(mrb); } @@ -129,7 +130,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) parameters_list[3].name = "opt"; } - aspec = GETARG_Ax(*irep->iseq); + aspec = PEEK_W(irep->iseq+1); parameters_list[0].size = MRB_ASPEC_REQ(aspec); parameters_list[1].size = MRB_ASPEC_OPT(aspec); parameters_list[2].size = MRB_ASPEC_REST(aspec); @@ -138,13 +139,16 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) parameters = mrb_ary_new_capa(mrb, irep->nlocals-1); + max = irep->nlocals-1; for (i = 0, p = parameters_list; p->name; p++) { if (p->size <= 0) continue; sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name)); for (j = 0; j < p->size; i++, j++) { - mrb_value a = mrb_ary_new(mrb); + mrb_value a; + + a = mrb_ary_new(mrb); mrb_ary_push(mrb, a, sname); - if (irep->lv[i].name) { + if (i < max && irep->lv[i].name) { mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name)); } mrb_ary_push(mrb, parameters, a); diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 4cab49094..142d449f4 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -627,8 +627,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE()); - mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ")); - mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!")); + mrb_define_alias(mrb, s, "next", "succ"); + mrb_define_alias(mrb, s, "next!", "succ!"); mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "delete_prefix!", mrb_str_del_prefix_bang, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "delete_prefix", mrb_str_del_prefix, MRB_ARGS_REQ(1)); diff --git a/src/class.c b/src/class.c index a9439d7d7..076280f3f 100644 --- a/src/class.c +++ b/src/class.c @@ -1953,8 +1953,8 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static void -undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) +void +mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a) { if (!mrb_obj_respond_to(mrb, c, a)) { mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); @@ -1970,7 +1970,7 @@ undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) { - undef_method(mrb, c, mrb_intern_cstr(mrb, name)); + mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name)); } MRB_API void @@ -1988,7 +1988,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - undef_method(mrb, c, to_sym(mrb, *argv)); + mrb_undef_method_id(mrb, c, to_sym(mrb, *argv)); argv++; } return mrb_nil_value(); diff --git a/src/codedump.c b/src/codedump.c index d79a65a70..22cbc59eb 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -6,451 +6,503 @@ #include #ifndef MRB_DISABLE_STDIO -static int -print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre) +static void +print_r(mrb_state *mrb, mrb_irep *irep, size_t n) { size_t i; - if (n == 0) return 0; + if (n == 0) return; for (i=0; i+1nlocals; i++) { if (irep->lv[i].r == n) { mrb_sym sym = irep->lv[i].name; - if (pre) printf(" "); - printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym)); - return 1; + printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym)); } } - return 0; } -#define RA 1 -#define RB 2 -#define RAB 3 - static void -print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r) +print_lv_a(mrb_state *mrb, mrb_irep *irep, uint16_t a) { - int pre = 0; - - if (!irep->lv - || ((!(r & RA) || GETARG_A(c) >= irep->nlocals) - && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) { + if (!irep->lv || a >= irep->nlocals || a == 0) { printf("\n"); return; } - printf("\t; "); - if (r & RA) { - pre = print_r(mrb, irep, GETARG_A(c), 0); - } - if (r & RB) { - print_r(mrb, irep, GETARG_B(c), pre); + printf("\t;"); + print_r(mrb, irep, a); + printf("\n"); +} + +static void +print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) +{ + if (!irep->lv || (a >= irep->nlocals && b >= irep->nlocals) || a+b == 0) { + printf("\n"); + return; } + printf("\t;"); + if (a > 0) print_r(mrb, irep, a); + if (b > 0) print_r(mrb, irep, b); printf("\n"); } #endif +static void +print_header(mrb_irep *irep, int i) +{ + int32_t line; + + line = mrb_debug_get_line(irep, i); + if (line < 0) { + printf(" "); + } + else { + printf("%5d ", line); + } + + printf("%03d ", i); +} + +#define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn + static void codedump(mrb_state *mrb, mrb_irep *irep) { #ifndef MRB_DISABLE_STDIO - int i; int ai; - mrb_code c; + mrb_code *pc, *pcend; + mrb_code ins; const char *file = NULL, *next_file; - int32_t line; if (!irep) return; printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); - for (i = 0; i < (int)irep->ilen; i++) { + pc = irep->iseq; + pcend = pc + irep->ilen; + while (pc < pcend) { + int i; + uint32_t a; + uint16_t b; + uint8_t c; + ai = mrb_gc_arena_save(mrb); + i = pc - irep->iseq; next_file = mrb_debug_get_filename(irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } - line = mrb_debug_get_line(irep, i); - if (line < 0) { - printf(" "); - } - else { - printf("%5d ", line); - } - - printf("%03d ", i); - c = irep->iseq[i]; - switch (GET_OPCODE(c)) { - case OP_NOP: + print_header(irep, i); + ins = READ_B(); + switch (ins) { + CASE(OP_NOP, Z): printf("OP_NOP\n"); break; - case OP_MOVE: - printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_MOVE, BB): + printf("OP_MOVE\tR%d\tR%d\t", a, b); + print_lv_ab(mrb, irep, a, b); break; - case OP_LOADL: + CASE(OP_LOADL, BB): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[b]; mrb_value s = mrb_inspect(mrb, v); - printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } - print_lv(mrb, irep, c, RA); - break; - case OP_LOADI: - printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSYM: - printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADNIL: - printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADSELF: - printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADT: - printf("OP_LOADT\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_LOADF: - printf("OP_LOADF\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETGLOBAL: - printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETGLOBAL: - printf("OP_SETGLOBAL\t:%s\tR%d\t", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCONST: - printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCONST: - printf("OP_SETCONST\t:%s\tR%d\t", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETMCNST: - printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RAB); - break; - case OP_SETMCNST: - printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1, - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETIV: - printf("OP_GETIV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETIV: - printf("OP_SETIV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETUPVAR: - printf("OP_GETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_SETUPVAR: - printf("OP_SETUPVAR\tR%d\t%d\t%d", - GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_GETCV: - printf("OP_GETCV\tR%d\t%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); - print_lv(mrb, irep, c, RA); - break; - case OP_SETCV: - printf("OP_SETCV\t%s\tR%d", - mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), - GETARG_A(c)); - print_lv(mrb, irep, c, RA); - break; - case OP_JMP: - printf("OP_JMP\t%03d (%d)\n", i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_JMPIF: - printf("OP_JMPIF\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_JMPNOT: - printf("OP_JMPNOT\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c)); - break; - case OP_SEND: - printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SENDB: - printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_CALL: - printf("OP_CALL\tR%d\n", GETARG_A(c)); - break; - case OP_TAILCALL: - printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUPER: - printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c), - GETARG_C(c)); - break; - case OP_ARGARY: - printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI, BB): + printf("OP_LOADI\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADINEG, BB): + printf("OP_LOADI\tR%d\t-%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI__1, B): + printf("OP_LOADI__1\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADI_0, B): goto L_LOADI; + CASE(OP_LOADI_1, B): goto L_LOADI; + CASE(OP_LOADI_2, B): goto L_LOADI; + CASE(OP_LOADI_3, B): goto L_LOADI; + CASE(OP_LOADI_4, B): goto L_LOADI; + CASE(OP_LOADI_5, B): goto L_LOADI; + CASE(OP_LOADI_6, B): goto L_LOADI; + CASE(OP_LOADI_7, B): + L_LOADI: + printf("OP_LOADI_%d\tR%d\t\t", ins-(int)OP_LOADI_0, a); + print_lv_a(mrb, irep, a); break; - - case OP_ENTER: + CASE(OP_LOADSYM, BB): + printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADNIL, B): + printf("OP_LOADNIL\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADSELF, B): + printf("OP_LOADSELF\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADT, B): + printf("OP_LOADT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LOADF, B): + printf("OP_LOADF\tR%d\t\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETGV, BB): + printf("OP_GETGV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETGV, BB): + printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETSV, BB): + printf("OP_GETSV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETSV, BB): + printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETCONST, BB): + printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETCONST, BB): + printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETMCNST, BB): + printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETMCNST, BB): + printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETIV, BB): + printf("OP_GETIV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETIV, BB): + printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETUPVAR, BBB): + printf("OP_GETUPVAR\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETUPVAR, BBB): + printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_GETCV, BB): + printf("OP_GETCV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SETCV, BB): + printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMP, S): + printf("OP_JMP\t\t%03d\n", a); + break; + CASE(OP_JMPIF, BS): + printf("OP_JMPIF\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMPNOT, BS): + printf("OP_JMPNOT\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_JMPNIL, BS): + printf("OP_JMPNIL\tR%d\t%03d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_SENDV, BB): + printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SENDVB, BB): + printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SEND, BBB): + printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_SENDB, BBB): + printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_CALL, Z): + printf("OP_CALL\n"); + break; + CASE(OP_SUPER, BB): + printf("OP_SUPER\tR%d\t%d\n", a, b); + break; + CASE(OP_ARGARY, BS): + printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", a, + (b>>10)&0x3f, + (b>>9)&0x1, + (b>>4)&0x1f, + (b>>0)&0xf); + print_lv_a(mrb, irep, a); + break; + CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (GETARG_Ax(c)>>18)&0x1f, - (GETARG_Ax(c)>>13)&0x1f, - (GETARG_Ax(c)>>12)&0x1, - (GETARG_Ax(c)>>7)&0x1f, - (GETARG_Ax(c)>>2)&0x1f, - (GETARG_Ax(c)>>1)&0x1, - GETARG_Ax(c) & 0x1); - break; - case OP_RETURN: - printf("OP_RETURN\tR%d", GETARG_A(c)); - switch (GETARG_B(c)) { - case OP_R_NORMAL: - printf("\tnormal\t"); break; - case OP_R_RETURN: - printf("\treturn\t"); break; - case OP_R_BREAK: - printf("\tbreak\t"); break; - default: - printf("\tbroken\t"); break; - } - print_lv(mrb, irep, c, RA); + (a>>18)&0x1f, + (a>>13)&0x1f, + (a>>12)&0x1, + (a>>7)&0x1f, + (a>>2)&0x1f, + (a>>1)&0x1, + a & 0x1); break; - case OP_BLKPUSH: - printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c), - (GETARG_Bx(c)>>10)&0x3f, - (GETARG_Bx(c)>>9)&0x1, - (GETARG_Bx(c)>>4)&0x1f, - (GETARG_Bx(c)>>0)&0xf); - print_lv(mrb, irep, c, RA); + CASE(OP_KARG, BB): + printf("OP_KARG\tR(%d)\tK(%d)\n", a, b); break; - - case OP_LAMBDA: - printf("OP_LAMBDA\tR%d\tI(%+d)\t", GETARG_A(c), GETARG_b(c)+1); - switch (GETARG_c(c)) { - case OP_L_METHOD: - printf("method"); break; - case OP_L_BLOCK: - printf("block"); break; - case OP_L_LAMBDA: - printf("lambda"); break; - } - print_lv(mrb, irep, c, RA); + CASE(OP_KARG2, BB): + printf("OP_KARG2\tR(%d)\tK(%d)\n", a, b); break; - case OP_RANGE: - printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_KDICT, B): + printf("OP_KDICt\tR(%d)\n", a); break; - case OP_METHOD: - printf("OP_METHOD\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_RETURN, B): + printf("OP_RETURN\tR%d", a); + print_lv_a(mrb, irep, a); break; - - case OP_ADD: - printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_ADDI: - printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUB: - printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_SUBI: - printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_MUL: - printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_DIV: - printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LT: - printf("OP_LT\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_LE: - printf("OP_LE\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GT: - printf("OP_GT\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_GE: - printf("OP_GE\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); - break; - case OP_EQ: - printf("OP_EQ\t\tR%d\t:%s\t%d\n", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), - GETARG_C(c)); + CASE(OP_RETURN_BLK, B): + printf("OP_RETURN_BLK\tR%d", a); + print_lv_a(mrb, irep, a); break; - - case OP_STOP: - printf("OP_STOP\n"); + CASE(OP_BREAK, B): + printf("OP_BREAK\tR%d", a); + print_lv_a(mrb, irep, a); break; - - case OP_ARRAY: - printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_BLKPUSH, BS): + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", a, + (b>>10)&0x3f, + (b>>9)&0x1, + (b>>4)&0x1f, + (b>>0)&0xf); + print_lv_a(mrb, irep, a); + break; + CASE(OP_LAMBDA, BB): + printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_BLOCK, BB): + printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_METHOD, BB): + printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); + break; + CASE(OP_RANGE_INC, B): + printf("OP_RANGE_INC\tR%d\n", a); + break; + CASE(OP_RANGE_EXC, B): + printf("OP_RANGE_EXC\tR%d\n", a); + break; + CASE(OP_DEF, BB): + printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_UNDEF, B): + printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a])); + break; + CASE(OP_ALIAS, BB): + printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_ADD, BB): + printf("OP_ADD\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_ADDI, BBB): + printf("OP_ADDI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_SUB, BB): + printf("OP_SUB\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_SUBI, BBB): + printf("OP_SUBI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + break; + CASE(OP_MUL, BB): + printf("OP_MUL\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_DIV, BB): + printf("OP_DIV\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_LT, BB): + printf("OP_LT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_LE, BB): + printf("OP_LE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_GT, BB): + printf("OP_GT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_GE, BB): + printf("OP_GE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + break; + CASE(OP_EQ, BB): + printf("OP_EQ\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); break; - case OP_ARYCAT: - printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARRAY, BB): + printf("OP_ARRAY\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); break; - case OP_ARYPUSH: - printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARRAY2, BBB): + printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c); + print_lv_ab(mrb, irep, a, b); break; - case OP_AREF: - printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_ARYCAT, B): + printf("OP_ARYCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_APOST: - printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_ARYPUSH, B): + printf("OP_ARYPUSH\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_STRING: + CASE(OP_ARYDUP, B): + printf("OP_ARYDUP\tR%d\t", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_AREF, BBB): + printf("OP_AREF\tR%d\tR%d\t%d", a, b, c); + print_lv_ab(mrb, irep, a, b); + break; + CASE(OP_ASET, BBB): + printf("OP_ASET\tR%d\tR%d\t%d", a, b, c); + print_lv_ab(mrb, irep, a, b); + break; + CASE(OP_APOST, BBB): + printf("OP_APOST\tR%d\t%d\t%d", a, b, c); + print_lv_a(mrb, irep, a); + break; + CASE(OP_INTERN, B): + printf("OP_INTERN\tR%d", a); + print_lv_a(mrb, irep, a); + break; + CASE(OP_STRING, BB): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[b]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); - printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); + printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } - print_lv(mrb, irep, c, RA); + print_lv_a(mrb, irep, a); + break; + CASE(OP_STRCAT, B): + printf("OP_STRCAT\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_STRCAT: - printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_HASH, BB): + printf("OP_HASH\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); break; - case OP_HASH: - printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_HASHADD, BB): + printf("OP_HASHADD\tR%d\t%d", a, b); + print_lv_a(mrb, irep, a); break; - case OP_OCLASS: - printf("OP_OCLASS\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_OCLASS, B): + printf("OP_OCLASS\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_CLASS: - printf("OP_CLASS\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_CLASS, BB): + printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_MODULE: - printf("OP_MODULE\tR%d\t:%s", GETARG_A(c), - mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); - print_lv(mrb, irep, c, RA); + CASE(OP_MODULE, BB): + printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - case OP_EXEC: - printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1); - print_lv(mrb, irep, c, RA); + CASE(OP_EXEC, BB): + printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, irep->reps[b]); + print_lv_a(mrb, irep, a); break; - case OP_SCLASS: - printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); - print_lv(mrb, irep, c, RAB); + CASE(OP_SCLASS, B): + printf("OP_SCLASS\tR%d\t", a); + print_lv_a(mrb, irep, a); break; - case OP_TCLASS: - printf("OP_TCLASS\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_TCLASS, B): + printf("OP_TCLASS\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_ERR: + CASE(OP_ERR, B): { - mrb_value v = irep->pool[GETARG_Bx(c)]; + mrb_value v = irep->pool[a]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); printf("OP_ERR\t%s\n", RSTRING_PTR(s)); } break; - case OP_EPUSH: - printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); + CASE(OP_EPUSH, B): + printf("OP_EPUSH\t\t:I(%d:%p)\n", a, irep->reps[a]); break; - case OP_ONERR: - printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); + CASE(OP_ONERR, S): + printf("OP_ONERR\t%03d\n", a); break; - case OP_RESCUE: - { - int a = GETARG_A(c); - int b = GETARG_B(c); - int cnt = GETARG_C(c); - - if (b == 0) { - printf("OP_RESCUE\tR%d\t\t%s", a, cnt ? "cont" : ""); - print_lv(mrb, irep, c, RA); - break; - } - else { - printf("OP_RESCUE\tR%d\tR%d\t%s", a, b, cnt ? "cont" : ""); - print_lv(mrb, irep, c, RAB); - break; - } - } + CASE(OP_EXCEPT, B): + printf("OP_EXCEPT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_RAISE: - printf("OP_RAISE\tR%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + CASE(OP_RESCUE, BB): + printf("OP_RESCUE\tR%d\tR%d", a, b); + print_lv_ab(mrb, irep, a, b); break; - case OP_POPERR: - printf("OP_POPERR\t%d\t\t\n", GETARG_A(c)); + CASE(OP_RAISE, B): + printf("OP_RAISE\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; - case OP_EPOP: - printf("OP_EPOP\t%d\n", GETARG_A(c)); + CASE(OP_POPERR, B): + printf("OP_POPERR\t%d\t\t\n", a); + break; + CASE(OP_EPOP, B): + printf("OP_EPOP\t%d\n", a); break; + CASE(OP_DEBUG, BBB): + printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c); + break; + + CASE(OP_STOP, Z): + printf("OP_STOP\n"); + break; + + CASE(OP_EXT1, Z): + ins = READ_B(); + printf("OP_EXT1\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + CASE(OP_EXT2, Z): + ins = READ_B(); + printf("OP_EXT2\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + CASE(OP_EXT3, Z): + ins = READ_B(); + printf("OP_EXT3\n"); + print_header(irep, pc-irep->iseq-2); + switch (ins) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: - printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c), - GETARG_A(c), GETARG_B(c), GETARG_C(c)); + printf("OP_unknown (0x%x)\n", ins); break; } mrb_gc_arena_restore(mrb, ai); diff --git a/src/kernel.c b/src/kernel.c index bbe6e8bb7..155868eaa 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1266,5 +1266,5 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); - mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone")); + mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/src/load.c b/src/load.c index ddf3cdfbf..20878aa56 100644 --- a/src/load.c +++ b/src/load.c @@ -79,7 +79,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag if ((flags & FLAG_SRC_MALLOC) == 0 && (flags & FLAG_BYTEORDER_NATIVE)) { irep->iseq = (mrb_code*)src; - src += sizeof(uint32_t) * irep->ilen; + src += sizeof(mrb_code) * irep->ilen; irep->flags |= MRB_ISEQ_NO_FREE; } else { diff --git a/src/proc.c b/src/proc.c index c6e9be433..05b897480 100644 --- a/src/proc.c +++ b/src/proc.c @@ -10,7 +10,7 @@ #include static mrb_code call_iseq[] = { - MKOP_A(OP_CALL, 0), + OP_CALL, }; struct RProc* @@ -223,7 +223,7 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); struct mrb_irep *irep; - mrb_code *iseq; + mrb_code *pc; mrb_aspec aspec; int ma, op, ra, pa, arity; @@ -237,13 +237,13 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(0); } - iseq = irep->iseq; + pc = irep->iseq; /* arity is depend on OP_ENTER */ - if (GET_OPCODE(*iseq) != OP_ENTER) { + if (*pc != OP_ENTER) { return mrb_fixnum_value(0); } - aspec = GETARG_Ax(*iseq); + aspec = PEEK_W(pc+1); ma = MRB_ASPEC_REQ(aspec); op = MRB_ASPEC_OPT(aspec); ra = MRB_ASPEC_REST(aspec); diff --git a/src/vm.c b/src/vm.c index 7a436828a..b50f1ee9f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -333,7 +333,7 @@ ecall(mrb_state *mrb) struct REnv *env; ptrdiff_t cioff; int ai = mrb_gc_arena_save(mrb); - int i = --c->eidx; + uint8_t i = --c->eidx; int nregs; if (i<0) return; @@ -911,18 +911,18 @@ argnum_error(mrb_state *mrb, mrb_int num) #ifndef DIRECT_THREADED -#define INIT_DISPATCH for (;;) { i = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) { -#define CASE(op) case op: -#define NEXT pc++; break -#define JUMP break +#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); pc++; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { +#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: +#define NEXT break +#define JUMP NEXT #define END_DISPATCH }} #else #define INIT_DISPATCH JUMP; return mrb_nil_value(); -#define CASE(op) L_ ## op: -#define NEXT i=BYTECODE_DECODER(*++pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] -#define JUMP i=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)] +#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); L_ ## insn ## _BODY: +#define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn] +#define JUMP NEXT #define END_DISPATCH @@ -958,6 +958,17 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac return result; } +static mrb_bool +check_target_class(mrb_state *mrb) +{ + if (!mrb->c->ci->target_class) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); + mrb_exc_set(mrb, exc); + return FALSE; + } + return TRUE; +} + MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { @@ -965,33 +976,19 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; - mrb_code i; + mrb_code insn; int ai = mrb_gc_arena_save(mrb); struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; + uint32_t a; + uint16_t b; + uint8_t c; #ifdef DIRECT_THREADED static void *optable[] = { - &&L_OP_NOP, &&L_OP_MOVE, - &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL, - &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF, - &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL, - &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV, - &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST, - &&L_OP_GETUPVAR, &&L_OP_SETUPVAR, - &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT, - &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP, - &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND, - &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER, - &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH, - &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV, - &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, - &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST, - &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH, - &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS, - &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC, - &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS, - &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR, +#define OPCODE(x,_) &&L_OP_ ## x, +#include "mruby/ops.h" +#undef OPCODE }; #endif @@ -1013,25 +1010,19 @@ RETRY_TRY_BLOCK: #define regs (mrb->c->stack) INIT_DISPATCH { - CASE(OP_NOP) { + CASE(OP_NOP, Z) { /* do nothing */ NEXT; } - CASE(OP_MOVE) { - /* A B R(A) := R(B) */ - int a = GETARG_A(i); - int b = GETARG_B(i); + CASE(OP_MOVE, BB) { regs[a] = regs[b]; NEXT; } - CASE(OP_LOADL) { - /* A Bx R(A) := Pool(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_LOADL, BB) { #ifdef MRB_WORD_BOXING - mrb_value val = pool[bx]; + mrb_value val = pool[b]; #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(val)) { val = mrb_float_value(mrb, mrb_float(val)); @@ -1039,125 +1030,110 @@ RETRY_TRY_BLOCK: #endif regs[a] = val; #else - regs[a] = pool[bx]; + regs[a] = pool[b]; #endif NEXT; } - CASE(OP_LOADI) { - /* A sBx R(A) := sBx */ - int a = GETARG_A(i); - mrb_int bx = GETARG_sBx(i); - SET_INT_VALUE(regs[a], bx); + CASE(OP_LOADI, BB) { + SET_INT_VALUE(regs[a], b); + NEXT; + } + + CASE(OP_LOADINEG, BB) { + SET_INT_VALUE(regs[a], -b); + NEXT; + } + + CASE(OP_LOADI__1,B) goto L_LOADI; + CASE(OP_LOADI_0,B) goto L_LOADI; + CASE(OP_LOADI_1,B) goto L_LOADI; + CASE(OP_LOADI_2,B) goto L_LOADI; + CASE(OP_LOADI_3,B) goto L_LOADI; + CASE(OP_LOADI_4,B) goto L_LOADI; + CASE(OP_LOADI_5,B) goto L_LOADI; + CASE(OP_LOADI_6,B) goto L_LOADI; + CASE(OP_LOADI_7, B) { + L_LOADI: + SET_INT_VALUE(regs[a], (mrb_int)insn - (mrb_int)OP_LOADI_0); + NEXT; + } + + CASE(OP_LOADSYM, BB) { + SET_SYM_VALUE(regs[a], syms[b]); NEXT; } - CASE(OP_LOADSYM) { - /* A Bx R(A) := Syms(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - SET_SYM_VALUE(regs[a], syms[bx]); + CASE(OP_LOADNIL, B) { + SET_NIL_VALUE(regs[a]); NEXT; } - CASE(OP_LOADSELF) { - /* A R(A) := self */ - int a = GETARG_A(i); + CASE(OP_LOADSELF, B) { regs[a] = regs[0]; NEXT; } - CASE(OP_LOADT) { - /* A R(A) := true */ - int a = GETARG_A(i); + CASE(OP_LOADT, B) { SET_TRUE_VALUE(regs[a]); NEXT; } - CASE(OP_LOADF) { - /* A R(A) := false */ - int a = GETARG_A(i); + CASE(OP_LOADF, B) { SET_FALSE_VALUE(regs[a]); NEXT; } - CASE(OP_GETGLOBAL) { - /* A Bx R(A) := getglobal(Syms(Bx)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_gv_get(mrb, syms[bx]); + CASE(OP_GETGV, BB) { + mrb_value val = mrb_gv_get(mrb, syms[b]); regs[a] = val; NEXT; } - CASE(OP_SETGLOBAL) { - /* A Bx setglobal(Syms(Bx), R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_gv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETGV, BB) { + mrb_gv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETSPECIAL) { - /* A Bx R(A) := Special[Bx] */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_vm_special_get(mrb, bx); + CASE(OP_GETSV, BB) { + mrb_value val = mrb_vm_special_get(mrb, b); regs[a] = val; NEXT; } - CASE(OP_SETSPECIAL) { - /* A Bx Special[Bx] := R(A) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_special_set(mrb, bx, regs[a]); + CASE(OP_SETSV, BB) { + mrb_vm_special_set(mrb, b, regs[a]); NEXT; } - CASE(OP_GETIV) { - /* A Bx R(A) := ivget(Bx) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_value val = mrb_vm_iv_get(mrb, syms[bx]); + CASE(OP_GETIV, BB) { + mrb_value val = mrb_vm_iv_get(mrb, syms[b]); regs[a] = val; NEXT; } - CASE(OP_SETIV) { - /* A Bx ivset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_iv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETIV, BB) { + mrb_vm_iv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETCV) { - /* A Bx R(A) := cvget(Syms(Bx)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_GETCV, BB) { mrb_value val; ERR_PC_SET(mrb, pc); - val = mrb_vm_cv_get(mrb, syms[bx]); + val = mrb_vm_cv_get(mrb, syms[b]); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETCV) { - /* A Bx cvset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_cv_set(mrb, syms[bx], regs[a]); + CASE(OP_SETCV, BB) { + mrb_vm_cv_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETCONST) { - /* A Bx R(A) := constget(Syms(Bx)) */ + CASE(OP_GETCONST, BB) { mrb_value val; - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_sym sym = syms[bx]; + mrb_sym sym = syms[b]; ERR_PC_SET(mrb, pc); val = mrb_vm_const_get(mrb, sym); @@ -1166,40 +1142,27 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_SETCONST) { - /* A Bx constset(Syms(Bx),R(A)) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_vm_const_set(mrb, syms[bx], regs[a]); + CASE(OP_SETCONST, BB) { + mrb_vm_const_set(mrb, syms[b], regs[a]); NEXT; } - CASE(OP_GETMCNST) { - /* A Bx R(A) := R(A)::Syms(Bx) */ + CASE(OP_GETMCNST, BB) { mrb_value val; - int a = GETARG_A(i); - int bx = GETARG_Bx(i); ERR_PC_SET(mrb, pc); - val = mrb_const_get(mrb, regs[a], syms[bx]); + val = mrb_const_get(mrb, regs[a], syms[b]); ERR_PC_CLR(mrb); regs[a] = val; NEXT; } - CASE(OP_SETMCNST) { - /* A Bx R(A+1)::Syms(Bx) := R(A) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]); + CASE(OP_SETMCNST, BB) { + mrb_const_set(mrb, regs[a+1], syms[b], regs[a]); NEXT; } - CASE(OP_GETUPVAR) { - /* A B C R(A) := uvget(B,C) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_GETUPVAR, BBB) { mrb_value *regs_a = regs + a; struct REnv *e = uvenv(mrb, c); @@ -1212,12 +1175,7 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_SETUPVAR) { - /* A B C uvset(B,C,R(A)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); - + CASE(OP_SETUPVAR, BBB) { struct REnv *e = uvenv(mrb, c); if (e) { @@ -1231,110 +1189,86 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_JMP) { - /* sBx pc+=sBx */ - int sbx = GETARG_sBx(i); - pc += sbx; + CASE(OP_JMP, S) { + pc = irep->iseq+a; JUMP; } - - CASE(OP_JMPIF) { - /* A sBx if R(A) pc+=sBx */ - int a = GETARG_A(i); - int sbx = GETARG_sBx(i); + CASE(OP_JMPIF, BS) { if (mrb_test(regs[a])) { - pc += sbx; + pc = irep->iseq+b; JUMP; } NEXT; } - - CASE(OP_JMPNOT) { - /* A sBx if !R(A) pc+=sBx */ - int a = GETARG_A(i); - int sbx = GETARG_sBx(i); + CASE(OP_JMPNOT, BS) { if (!mrb_test(regs[a])) { - pc += sbx; + pc = irep->iseq+b; + JUMP; + } + NEXT; + } + CASE(OP_JMPNIL, BS) { + if (mrb_nil_p(regs[a])) { + pc = irep->iseq+b; JUMP; } NEXT; } - CASE(OP_ONERR) { - /* sBx pc+=sBx on exception */ - int sbx = GETARG_sBx(i); + CASE(OP_ONERR, S) { if (mrb->c->rsize <= mrb->c->ci->ridx) { if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE; else mrb->c->rsize *= 2; - mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize); + mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t) * mrb->c->rsize); } - mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx; + mrb->c->rescue[mrb->c->ci->ridx++] = a; NEXT; } - CASE(OP_RESCUE) { - /* A B R(A) := exc; clear(exc); R(B) := matched (bool) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); - mrb_value exc; - - if (c == 0) { - exc = mrb_obj_value(mrb->exc); - mrb->exc = 0; - } - else { /* continued; exc taken from R(A) */ - exc = regs[a]; - } - if (b != 0) { - mrb_value e = regs[b]; - struct RClass *ec; + CASE(OP_EXCEPT, B) { + mrb_value exc = mrb_obj_value(mrb->exc); + mrb->exc = 0; + regs[a] = exc; + NEXT; + } + CASE(OP_RESCUE, BB) { + mrb_value exc = regs[a]; /* exc on stack */ + mrb_value e = regs[b]; + struct RClass *ec; - switch (mrb_type(e)) { - case MRB_TT_CLASS: - case MRB_TT_MODULE: - break; - default: - { - mrb_value exc; + switch (mrb_type(e)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + break; + default: + { + mrb_value exc; - exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, - "class or module required for rescue clause"); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } + exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, + "class or module required for rescue clause"); + mrb_exc_set(mrb, exc); + goto L_RAISE; } - ec = mrb_class_ptr(e); - regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); - } - if (a != 0 && c == 0) { - regs[a] = exc; } + ec = mrb_class_ptr(e); + regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec)); NEXT; } - CASE(OP_POPERR) { - /* A A.times{rescue_pop()} */ - int a = GETARG_A(i); - + CASE(OP_POPERR, B) { mrb->c->ci->ridx -= a; NEXT; } - CASE(OP_RAISE) { - /* A raise(R(A)) */ - int a = GETARG_A(i); - + CASE(OP_RAISE, B) { mrb_exc_set(mrb, regs[a]); goto L_RAISE; } - CASE(OP_EPUSH) { - /* Bx ensure_push(SEQ[Bx]) */ - int bx = GETARG_Bx(i); + CASE(OP_EPUSH, B) { struct RProc *p; - p = mrb_closure_new(mrb, irep->reps[bx]); + p = mrb_closure_new(mrb, irep->reps[a]); /* push ensure_stack */ if (mrb->c->esize <= mrb->c->eidx+1) { if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE; @@ -1347,11 +1281,9 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_EPOP) { - /* A A.times{ensure_pop().call} */ - int a = GETARG_A(i); + CASE(OP_EPOP, B) { mrb_callinfo *ci = mrb->c->ci; - int n, epos = ci->epos; + unsigned int n, epos = ci->epos; mrb_value self = regs[0]; struct RClass *target_class = ci->target_class; @@ -1359,9 +1291,8 @@ RETRY_TRY_BLOCK: NEXT; } - if (a > mrb->c->eidx - epos) + if (a > (int)mrb->c->eidx - epos) a = mrb->c->eidx - epos; - pc = pc + 1; for (n=0; nc->ensure[epos+n]; mrb->c->ensure[epos+n] = NULL; @@ -1387,29 +1318,32 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_LOADNIL) { - /* A R(A) := nil */ - int a = GETARG_A(i); + CASE(OP_SENDV, BB) { + c = CALL_MAXARGS; + goto L_SEND; + }; - SET_NIL_VALUE(regs[a]); - NEXT; - } + CASE(OP_SENDVB, BB) { + c = CALL_MAXARGS; + goto L_SENDB; + }; - CASE(OP_SENDB) { - /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/ - /* fall through */ + CASE(OP_SEND, BBB) + L_SEND: + { + /* push nil after arguments */ + int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; + SET_NIL_VALUE(regs[bidx]); + goto L_SENDB; }; - L_SEND: - CASE(OP_SEND) { - /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int n = GETARG_C(i); - int argc = (n == CALL_MAXARGS) ? -1 : n; - int bidx = (argc < 0) ? a+2 : a+n+1; + CASE(OP_SENDB, BBB) + L_SENDB: + { + int argc = (c == CALL_MAXARGS) ? -1 : c; + int bidx = (argc < 0) ? a+2 : a+c+1; mrb_method_t m; - struct RClass *c; + struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; mrb_sym mid = syms[b]; @@ -1417,26 +1351,20 @@ RETRY_TRY_BLOCK: mrb_assert(bidx < ci->nregs); recv = regs[a]; - if (GET_OPCODE(i) != OP_SENDB) { - SET_NIL_VALUE(regs[bidx]); - blk = regs[bidx]; - } - else { - blk = regs[bidx]; - if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { - blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); - /* The stack might have been reallocated during mrb_convert_type(), - see #3622 */ - regs[bidx] = blk; - } + blk = regs[bidx]; + if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); + /* The stack might have been reallocated during mrb_convert_type(), + see #3622 */ + regs[bidx] = blk; } - c = mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &c, mid); + cls = mrb_class(mrb, recv); + m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, missing); + m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1); ERR_PC_SET(mrb, pc); mrb_method_missing(mrb, mid, recv, args); } @@ -1444,7 +1372,7 @@ RETRY_TRY_BLOCK: if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); } - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+1] = mrb_ary_new_from_values(mrb, c, regs+a+1); regs[a+2] = blk; argc = -1; } @@ -1456,17 +1384,17 @@ RETRY_TRY_BLOCK: ci = cipush(mrb); ci->mid = mid; ci->stackent = mrb->c->stack; - ci->target_class = c; + ci->target_class = cls; ci->argc = argc; - ci->pc = pc + 1; + ci->pc = pc; ci->acc = a; /* prepare stack */ mrb->c->stack += a; if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (argc < 0) ? 3 : n+2; + ci->nregs = (argc < 0) ? 3 : c+2; if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); @@ -1480,12 +1408,10 @@ RETRY_TRY_BLOCK: mrb_gc_arena_shrink(mrb, ai); if (mrb->exc) goto L_RAISE; ci = mrb->c->ci; - if (GET_OPCODE(i) == OP_SENDB) { - if (mrb_type(blk) == MRB_TT_PROC) { - struct RProc *p = mrb_proc_ptr(blk); - if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { - p->flags |= MRB_PROC_ORPHAN; - } + if (mrb_type(blk) == MRB_TT_PROC) { + struct RProc *p = mrb_proc_ptr(blk); + if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { + p->flags |= MRB_PROC_ORPHAN; } } if (!ci->target_class) { /* return from context modifying method (resume/yield) */ @@ -1521,14 +1447,7 @@ RETRY_TRY_BLOCK: } } - CASE(OP_FSEND) { - /* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */ - /* not implemented yet */ - NEXT; - } - - CASE(OP_CALL) { - /* A R(A) := self.call(frame.argc, frame.argv) */ + CASE(OP_CALL, Z) { mrb_callinfo *ci; mrb_value recv = mrb->c->stack[0]; struct RProc *m = mrb_proc_ptr(recv); @@ -1571,7 +1490,9 @@ RETRY_TRY_BLOCK: irep = m->body.irep; if (!irep) { mrb->c->stack[0] = mrb_nil_value(); - goto L_RETURN; + a = 0; + c = OP_R_NORMAL; + goto L_OP_RETURN_BODY; } pool = irep->pool; syms = irep->syms; @@ -1593,14 +1514,11 @@ RETRY_TRY_BLOCK: } } - CASE(OP_SUPER) { - /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */ - int a = GETARG_A(i); - int n = GETARG_C(i); - int argc = (n == CALL_MAXARGS) ? -1 : n; - int bidx = (argc < 0) ? a+2 : a+n+1; + CASE(OP_SUPER, BB) { + int argc = (b == CALL_MAXARGS) ? -1 : b; + int bidx = (argc < 0) ? a+2 : a+b+1; mrb_method_t m; - struct RClass *c; + struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; mrb_sym mid = ci->mid; @@ -1636,17 +1554,17 @@ RETRY_TRY_BLOCK: regs[bidx] = blk; ci = mrb->c->ci; } - c = target_class->super; - m = mrb_method_search_vm(mrb, &c, mid); + cls = target_class->super; + m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); if (mid != missing) { - c = mrb_class(mrb, recv); + cls = mrb_class(mrb, recv); } - m = mrb_method_search_vm(mrb, &c, missing); + m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m)) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1); + mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); ERR_PC_SET(mrb, pc); mrb_method_missing(mrb, mid, recv, args); } @@ -1655,7 +1573,7 @@ RETRY_TRY_BLOCK: if (a+2 >= ci->nregs) { mrb_stack_extend(mrb, a+3); } - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + regs[a+1] = mrb_ary_new_from_values(mrb, b, regs+a+1); regs[a+2] = blk; argc = -1; } @@ -1666,8 +1584,8 @@ RETRY_TRY_BLOCK: ci = cipush(mrb); ci->mid = mid; ci->stackent = mrb->c->stack; - ci->target_class = c; - ci->pc = pc + 1; + ci->target_class = cls; + ci->pc = pc; ci->argc = argc; /* prepare stack */ @@ -1676,7 +1594,7 @@ RETRY_TRY_BLOCK: if (MRB_METHOD_CFUNC_P(m)) { mrb_value v; - ci->nregs = (argc < 0) ? 3 : n+2; + ci->nregs = (argc < 0) ? 3 : b+2; if (MRB_METHOD_PROC_P(m)) { ci->proc = MRB_METHOD_PROC(m); } @@ -1720,14 +1638,11 @@ RETRY_TRY_BLOCK: } } - CASE(OP_ARGARY) { - /* A Bx R(A) := argument array (16=6:1:5:4) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - int m1 = (bx>>10)&0x3f; - int r = (bx>>9)&0x1; - int m2 = (bx>>4)&0x1f; - int lv = (bx>>0)&0xf; + CASE(OP_ARGARY, BS) { + int m1 = (b>>10)&0x3f; + int r = (b>>9)&0x1; + int m2 = (b>>4)&0x1f; + int lv = (b>>0)&0xf; mrb_value *stack; if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) { @@ -1778,18 +1693,15 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ENTER) { - /* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */ - /* number of optional arguments times OP_JMP should follow */ - mrb_aspec ax = GETARG_Ax(i); - int m1 = MRB_ASPEC_REQ(ax); - int o = MRB_ASPEC_OPT(ax); - int r = MRB_ASPEC_REST(ax); - int m2 = MRB_ASPEC_POST(ax); + CASE(OP_ENTER, W) { + int m1 = MRB_ASPEC_REQ(a); + int o = MRB_ASPEC_OPT(a); + int r = MRB_ASPEC_REST(a); + int m2 = MRB_ASPEC_POST(a); /* unused - int k = MRB_ASPEC_KEY(ax); - int kd = MRB_ASPEC_KDICT(ax); - int b = MRB_ASPEC_BLOCK(ax); + int k = MRB_ASPEC_KEY(a); + int kd = MRB_ASPEC_KDICT(a); + int b = MRB_ASPEC_BLOCK(a); */ int argc = mrb->c->ci->argc; mrb_value *argv = regs+1; @@ -1841,9 +1753,8 @@ RETRY_TRY_BLOCK: if (r) { regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } - if (o == 0 || argc < m1+m2) pc++; - else - pc += argc - m1 - m2 + 1; + if (o > 0 && argc >= m1+m2) + pc += (argc - m1 - m2)*3; } else { int rnum = 0; @@ -1852,8 +1763,11 @@ RETRY_TRY_BLOCK: value_move(®s[1], argv, m1+o); } if (r) { + mrb_value ary; + rnum = argc-m1-o-m2; - regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); + regs[m1+o+1] = ary; } if (m2) { if (argc-m2 > m1) { @@ -1863,7 +1777,7 @@ RETRY_TRY_BLOCK: if (argv0 == argv) { regs[len+1] = *blk; /* move block */ } - pc += o + 1; + pc += o*3; } mrb->c->ci->argc = len; /* clear local (but non-argument) variables */ @@ -1873,24 +1787,33 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_KARG) { - /* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */ - /* if C == 2; raise unless kdict.empty? */ - /* OP_JMP should follow to skip init code */ + CASE(OP_KARG, BB) { + /* not implemented yet */ + NEXT; + } + CASE(OP_KARG2, BB) { + /* not implemented yet */ NEXT; } - CASE(OP_KDICT) { - /* A C R(A) := kdict */ + CASE(OP_KDICT, B) { + /* not implemented yet */ NEXT; } + CASE(OP_BREAK, B) { + c = OP_R_BREAK; + goto L_RETURN; + } + CASE(OP_RETURN_BLK, B) { + c = OP_R_RETURN; + goto L_RETURN; + } + CASE(OP_RETURN, B) + c = OP_R_NORMAL; L_RETURN: - i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL); - /* fall through */ - CASE(OP_RETURN) { - /* A B return R(A) (B=normal,in-block return/break) */ - mrb_callinfo *ci; + { + mrb_callinfo *ci; #define ecall_adjust() do {\ ptrdiff_t cioff = ci - mrb->c->cibase;\ @@ -1976,7 +1899,7 @@ RETRY_TRY_BLOCK: mrb->c->stack = ci[1].stackent; } mrb_stack_extend(mrb, irep->nregs); - pc = mrb->c->rescue[--ci->ridx]; + pc = irep->iseq+mrb->c->rescue[--ci->ridx]; } else { int acc; @@ -1984,9 +1907,9 @@ RETRY_TRY_BLOCK: struct RProc *dst; ci = mrb->c->ci; - v = regs[GETARG_A(i)]; + v = regs[a]; mrb_gc_protect(mrb, v); - switch (GETARG_B(i)) { + switch (c) { case OP_R_RETURN: /* Fall through to OP_R_NORMAL otherwise */ if (ci->acc >=0 && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) { @@ -2021,8 +1944,7 @@ RETRY_TRY_BLOCK: struct mrb_context *c; if (!mrb->c->prev) { /* toplevel return */ - localjump_error(mrb, LOCALJUMP_ERROR_RETURN); - goto L_RAISE; + goto L_STOP; } if (mrb->c->prev->ci == mrb->c->prev->cibase) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); @@ -2141,91 +2063,11 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_TAILCALL) { - /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int n = GETARG_C(i); - mrb_method_t m; - struct RClass *c; - mrb_callinfo *ci; - mrb_value recv; - mrb_sym mid = syms[b]; - - recv = regs[a]; - c = mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &c, mid); - if (MRB_METHOD_UNDEF_P(m)) { - mrb_value sym = mrb_symbol_value(mid); - mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, missing); - if (MRB_METHOD_UNDEF_P(m)) { - mrb_value args; - - if (n == CALL_MAXARGS) { - args = regs[a+1]; - } - else { - args = mrb_ary_new_from_values(mrb, n, regs+a+1); - } - ERR_PC_SET(mrb, pc); - mrb_method_missing(mrb, mid, recv, args); - } - mid = missing; - if (n == CALL_MAXARGS) { - mrb_ary_unshift(mrb, regs[a+1], sym); - } - else { - value_move(regs+a+2, regs+a+1, ++n); - regs[a+1] = sym; - } - } - - /* replace callinfo */ - ci = mrb->c->ci; - ci->mid = mid; - ci->target_class = c; - if (n == CALL_MAXARGS) { - ci->argc = -1; - } - else { - ci->argc = n; - } - - /* move stack */ - value_move(mrb->c->stack, ®s[a], ci->argc+1); - - if (MRB_METHOD_CFUNC_P(m)) { - mrb_value v = MRB_METHOD_CFUNC(m)(mrb, recv); - mrb->c->stack[0] = v; - mrb_gc_arena_restore(mrb, ai); - goto L_RETURN; - } - else { - /* setup environment for calling method */ - struct RProc *p = MRB_METHOD_PROC(m); - irep = p->body.irep; - pool = irep->pool; - syms = irep->syms; - if (ci->argc < 0) { - mrb_stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs); - } - else { - mrb_stack_extend(mrb, irep->nregs); - } - pc = irep->iseq; - } - JUMP; - } - - CASE(OP_BLKPUSH) { - /* A Bx R(A) := block (16=6:1:5:4) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); - int m1 = (bx>>10)&0x3f; - int r = (bx>>9)&0x1; - int m2 = (bx>>4)&0x1f; - int lv = (bx>>0)&0xf; + CASE(OP_BLKPUSH, BS) { + int m1 = (b>>10)&0x3f; + int r = (b>>9)&0x1; + int m2 = (b>>4)&0x1f; + int lv = (b>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; @@ -2251,10 +2093,7 @@ RETRY_TRY_BLOCK: v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ } while(0) - CASE(OP_ADD) { - /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_ADD, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2308,16 +2147,14 @@ RETRY_TRY_BLOCK: regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); break; default: + c = 1; goto L_SEND; } mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SUB) { - /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_SUB, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2367,15 +2204,13 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } NEXT; } - CASE(OP_MUL) { - /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ - int a = GETARG_A(i); - + CASE(OP_MUL, BB) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2425,14 +2260,13 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } NEXT; } - CASE(OP_DIV) { - /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ - int a = GETARG_A(i); + CASE(OP_DIV, BB) { #ifndef MRB_WITHOUT_FLOAT double x, y, f; #endif @@ -2465,6 +2299,7 @@ RETRY_TRY_BLOCK: break; #endif default: + c = 1; goto L_SEND; } @@ -2482,16 +2317,13 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI) { - /* A B C R(A) := R(A)+C (Syms[B]=:+)*/ - int a = GETARG_A(i); - + CASE(OP_ADDI, BBB) { /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = GETARG_C(i); + mrb_int y = (mrb_int)c; mrb_int z; if (mrb_int_add_overflow(x, y, &z)) { @@ -2508,24 +2340,22 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i)); + SET_FLOAT_VALUE(mrb, regs[a], x + c); } #else - mrb_float(regs[a]) += GETARG_C(i); + mrb_float(regs[a]) += c; #endif break; #endif default: - SET_INT_VALUE(regs[a+1], GETARG_C(i)); - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); + SET_INT_VALUE(regs[a+1], c); + c = 1; goto L_SEND; } NEXT; } - CASE(OP_SUBI) { - /* A B C R(A) := R(A)-C (Syms[B]=:-)*/ - int a = GETARG_A(i); + CASE(OP_SUBI, BBB) { mrb_value *regs_a = regs + a; /* need to check if + is overridden */ @@ -2533,7 +2363,7 @@ RETRY_TRY_BLOCK: case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = GETARG_C(i); + mrb_int y = (mrb_int)c; mrb_int z; if (mrb_int_sub_overflow(x, y, &z)) { @@ -2553,13 +2383,13 @@ RETRY_TRY_BLOCK: SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i)); } #else - mrb_float(regs_a[0]) -= GETARG_C(i); + mrb_float(regs_a[0]) -= c; #endif break; #endif default: - SET_INT_VALUE(regs_a[1], GETARG_C(i)); - i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); + SET_INT_VALUE(regs_a[1], c); + c = 1; goto L_SEND; } NEXT; @@ -2576,6 +2406,7 @@ RETRY_TRY_BLOCK: result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\ break;\ default:\ + c = 1;\ goto L_SEND;\ }\ if (result) {\ @@ -2603,6 +2434,7 @@ RETRY_TRY_BLOCK: result = OP_CMP_BODY(op,mrb_float,mrb_float);\ break;\ default:\ + c = 1;\ goto L_SEND;\ }\ if (result) {\ @@ -2614,9 +2446,7 @@ RETRY_TRY_BLOCK: } while(0) #endif - CASE(OP_EQ) { - /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/ - int a = GETARG_A(i); + CASE(OP_EQ, BB) { if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { SET_TRUE_VALUE(regs[a]); } @@ -2626,68 +2456,59 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_LT) { - /* A B C R(A) := R(A)R(A+1) (Syms[B]=:>,C=1)*/ - int a = GETARG_A(i); + CASE(OP_GT, BB) { OP_CMP(>); NEXT; } - CASE(OP_GE) { - /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/ - int a = GETARG_A(i); + CASE(OP_GE, BB) { OP_CMP(>=); NEXT; } - CASE(OP_ARRAY) { - /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ARRAY, BB) { + mrb_value v = mrb_ary_new_from_values(mrb, b, ®s[a]); + regs[a] = v; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + CASE(OP_ARRAY2, BBB) { mrb_value v = mrb_ary_new_from_values(mrb, c, ®s[b]); regs[a] = v; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYCAT) { - /* A B mrb_ary_concat(R(A),R(B)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - mrb_value splat = mrb_ary_splat(mrb, regs[b]); + CASE(OP_ARYCAT, B) { + mrb_value splat = mrb_ary_splat(mrb, regs[a+1]); mrb_ary_concat(mrb, regs[a], splat); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_ARYPUSH) { - /* A B R(A).push(R(B)) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - mrb_ary_push(mrb, regs[a], regs[b]); + CASE(OP_ARYPUSH, B) { + mrb_ary_push(mrb, regs[a], regs[a+1]); NEXT; } - CASE(OP_AREF) { - /* A B C R(A) := R(B)[C] */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ARYDUP, B) { + mrb_value ary = regs[a]; + ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + regs[a] = ary; + NEXT; + } + + CASE(OP_AREF, BBB) { mrb_value v = regs[b]; if (!mrb_array_p(v)) { @@ -2705,21 +2526,15 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ASET) { - /* A B C R(B)[C] := R(A) */ - int a = GETARG_A(i); - int b = GETARG_B(i); - int c = GETARG_C(i); + CASE(OP_ASET, BBB) { mrb_ary_set(mrb, regs[b], c, regs[a]); NEXT; } - CASE(OP_APOST) { - /* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */ - int a = GETARG_A(i); + CASE(OP_APOST, BBB) { mrb_value v = regs[a]; - int pre = GETARG_B(i); - int post = GETARG_C(i); + int pre = b; + int post = c; struct RArray *ary; int len, idx; @@ -2750,48 +2565,58 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_STRING) { - /* A Bx R(A) := str_new(Lit(Bx)) */ - mrb_int a = GETARG_A(i); - mrb_int bx = GETARG_Bx(i); - mrb_value str = mrb_str_dup(mrb, pool[bx]); + CASE(OP_INTERN, B) { + mrb_sym sym = mrb_intern_str(mrb, regs[a]); + + regs[a] = mrb_symbol_value(sym); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_STRING, BB) { + mrb_value str = mrb_str_dup(mrb, pool[b]); regs[a] = str; mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_STRCAT) { - /* A B R(A).concat(R(B)) */ - mrb_int a = GETARG_A(i); - mrb_int b = GETARG_B(i); + CASE(OP_STRCAT, B) { + mrb_str_concat(mrb, regs[a], regs[a+1]); + NEXT; + } + + CASE(OP_HASH, BB) { + mrb_value hash = mrb_hash_new_capa(mrb, b); + int i; + int lim = a+b*2; - mrb_str_concat(mrb, regs[a], regs[b]); + for (i=a; ireps[b]; if (c & OP_L_CAPTURE) { @@ -2806,19 +2631,38 @@ RETRY_TRY_BLOCK: mrb_gc_arena_restore(mrb, ai); NEXT; } + CASE(OP_BLOCK, BB) { + c = OP_L_BLOCK; + goto L_MAKE_LAMBDA; + } + CASE(OP_METHOD, BB) { + c = OP_L_METHOD; + goto L_MAKE_LAMBDA; + } - CASE(OP_OCLASS) { - /* A R(A) := ::Object */ - regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class); + CASE(OP_RANGE_INC, B) { + mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], FALSE); + regs[a] = val; + mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_CLASS) { - /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ + CASE(OP_RANGE_EXC, B) { + mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], TRUE); + regs[a] = val; + mrb_gc_arena_restore(mrb, ai); + NEXT; + } + + CASE(OP_OCLASS, B) { + regs[a] = mrb_obj_value(mrb->object_class); + NEXT; + } + + CASE(OP_CLASS, BB) { struct RClass *c = 0, *baseclass; - int a = GETARG_A(i); mrb_value base, super; - mrb_sym id = syms[GETARG_B(i)]; + mrb_sym id = syms[b]; base = regs[a]; super = regs[a+1]; @@ -2832,32 +2676,27 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_MODULE) { - /* A B R(A) := newmodule(R(A),Syms(B)) */ - struct RClass *c = 0, *baseclass; - int a = GETARG_A(i); + CASE(OP_MODULE, BB) { + struct RClass *cls = 0, *baseclass; mrb_value base; - mrb_sym id = syms[GETARG_B(i)]; + mrb_sym id = syms[b]; base = regs[a]; if (mrb_nil_p(base)) { baseclass = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); base = mrb_obj_value(baseclass); } - c = mrb_vm_define_module(mrb, base, id); - regs[a] = mrb_obj_value(c); + cls = mrb_vm_define_module(mrb, base, id); + regs[a] = mrb_obj_value(cls); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_EXEC) { - /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ - int a = GETARG_A(i); - int bx = GETARG_Bx(i); + CASE(OP_EXEC, BB) { mrb_callinfo *ci; mrb_value recv = regs[a]; struct RProc *p; - mrb_irep *nirep = irep->reps[bx]; + mrb_irep *nirep = irep->reps[b]; /* prepare closure */ p = mrb_proc_new(mrb, nirep); @@ -2868,7 +2707,7 @@ RETRY_TRY_BLOCK: /* prepare call stack */ ci = cipush(mrb); - ci->pc = pc + 1; + ci->pc = pc; ci->acc = a; ci->mid = 0; ci->stackent = mrb->c->stack; @@ -2891,56 +2730,53 @@ RETRY_TRY_BLOCK: JUMP; } - CASE(OP_METHOD) { - /* A B R(A).newmethod(Syms(B),R(A+1)) */ - int a = GETARG_A(i); - struct RClass *c = mrb_class_ptr(regs[a]); + CASE(OP_DEF, BB) { + struct RClass *target = mrb_class_ptr(regs[a]); struct RProc *p = mrb_proc_ptr(regs[a+1]); mrb_method_t m; MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], m); + mrb_define_method_raw(mrb, target, syms[b], m); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SCLASS) { - /* A B R(A) := R(B).singleton_class */ - int a = GETARG_A(i); - int b = GETARG_B(i); - - regs[a] = mrb_singleton_class(mrb, regs[b]); + CASE(OP_SCLASS, B) { + regs[a] = mrb_singleton_class(mrb, regs[a]); mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_TCLASS) { - /* A R(A) := target_class */ - if (!mrb->c->ci->target_class) { - mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module"); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } - regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class); + CASE(OP_TCLASS, B) { + if (!check_target_class(mrb)) goto L_RAISE; + regs[a] = mrb_obj_value(mrb->c->ci->target_class); NEXT; } - CASE(OP_RANGE) { - /* A B C R(A) := range_new(R(B),R(B+1),C) */ - int b = GETARG_B(i); - mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); - regs[GETARG_A(i)] = val; - mrb_gc_arena_restore(mrb, ai); + CASE(OP_ALIAS, BB) { + struct RClass *target; + + if (!check_target_class(mrb)) goto L_RAISE; + target = mrb->c->ci->target_class; + mrb_alias_method(mrb, target, syms[a], syms[b]); + NEXT; + } + CASE(OP_UNDEF, B) { + struct RClass *target; + + if (!check_target_class(mrb)) goto L_RAISE; + target = mrb->c->ci->target_class; + mrb_undef_method_id(mrb, target, syms[a]); NEXT; } - CASE(OP_DEBUG) { - /* A B C debug print R(A),R(B),R(C) */ + CASE(OP_DEBUG, Z) { + FETCH_BBB(); #ifdef MRB_ENABLE_DEBUG_HOOK mrb->debug_op_hook(mrb, irep, pc, regs); #else #ifndef MRB_DISABLE_STDIO - printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i)); + printf("OP_DEBUG %d %d %d\n", a, b, c); #else abort(); #endif @@ -2948,7 +2784,48 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_STOP) { + CASE(OP_ERR, B) { + mrb_value msg = mrb_str_dup(mrb, pool[a]); + mrb_value exc; + + exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); + ERR_PC_SET(mrb, pc); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + + CASE(OP_EXT1, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_EXT2, Z) { + insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _2(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + CASE(OP_EXT3, Z) { + uint8_t insn = READ_B(); + switch (insn) { +#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _3(); goto L_OP_ ## insn ## _BODY; +#include "mruby/ops.h" +#undef OPCODE + } + pc--; + NEXT; + } + + CASE(OP_STOP, Z) { /* stop VM */ L_STOP: while (mrb->c->eidx > 0) { @@ -2961,26 +2838,9 @@ RETRY_TRY_BLOCK: } return regs[irep->nlocals]; } - - CASE(OP_ERR) { - /* Bx raise RuntimeError with message Lit(Bx) */ - mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]); - mrb_value exc; - - if (GETARG_A(i) == 0) { - exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg); - } - else { - exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); - } - ERR_PC_SET(mrb, pc); - mrb_exc_set(mrb, exc); - goto L_RAISE; - } } END_DISPATCH; #undef regs - } MRB_CATCH(&c_jmp) { exc_catched = TRUE; -- cgit v1.2.3 From 8c9e7127845f84fcbb249c45936c97a89ca7a80a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 30 Jul 2018 22:07:31 +0900 Subject: Keyword argument implemented. --- doc/opcode.md | 8 +- include/mruby/hash.h | 27 +- include/mruby/ops.h | 11 +- mrbgems/mruby-compiler/core/codegen.c | 149 +++++-- mrbgems/mruby-compiler/core/node.h | 4 + mrbgems/mruby-compiler/core/parse.y | 493 ++++++++++++++-------- mrbgems/mruby-objectspace/src/mruby_objectspace.c | 2 +- mrbgems/mruby-proc-ext/src/proc.c | 10 +- src/codedump.c | 50 ++- src/hash.c | 86 +++- src/kernel.c | 10 +- src/vm.c | 146 +++++-- test/t/syntax.rb | 183 ++++++++ 13 files changed, 887 insertions(+), 292 deletions(-) (limited to 'src') diff --git a/doc/opcode.md b/doc/opcode.md index d904256e5..54d1f0553 100644 --- a/doc/opcode.md +++ b/doc/opcode.md @@ -77,7 +77,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) |OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) |OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) -|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) +|OP_ARGARY' |BS |R(a) = argument array (16=5:1:5:1:4) |OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) |OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo |OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo @@ -85,7 +85,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_RETURN' |B |return R(a) (normal) |OP_RETURN_BLK' |B |return R(a) (in-block return) |OP_BREAK' |B |break R(a) -|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) +|OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4) |OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) |OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) |OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) @@ -207,7 +207,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) |OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv) |OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) -|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) +|OP_ARGARY' |BS |R(a) = argument array (16=5:1:5:1:4) |OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1) |OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo |OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo @@ -215,7 +215,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. |OP_RETURN' |B |return R(a) (normal) |OP_RETURN_BLK' |B |return R(a) (in-block return) |OP_BREAK' |B |break R(a) -|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) +|OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4) |OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+) |OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+) |OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 1a870785a..9a3812850 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -25,6 +25,7 @@ struct RHash { #define mrb_hash_value(p) mrb_obj_value((void*)(p)) MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int); +MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); /* * Initializes a new hash. @@ -110,7 +111,19 @@ MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value * @return An array with the keys of the hash. */ MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash); -MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); +/* + * Check if the hash has the key. + * + * Equivalent to: + * + * hash.key?(key) + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to check existence. + * @return True if the hash has the key + */ +MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key); /* * Check if the hash is empty @@ -123,7 +136,7 @@ MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); * @param self The target hash. * @return True if the hash is empty, false otherwise. */ -MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self); +MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self); /* * Gets an array of values. @@ -151,6 +164,16 @@ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash); */ MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); +/* + * Copies the hash. + * + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return The copy of the hash + */ +MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash); + /* declaration of struct kh_ht */ /* be careful when you touch the internal */ typedef struct { diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 882ad6f25..9675d6158 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -61,15 +61,16 @@ OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) */ OPCODE(SENDB, BBB) /* R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) */ OPCODE(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */ OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */ -OPCODE(ARGARY, BS) /* R(a) = argument array (16=6:1:5:4) */ -OPCODE(ENTER, W) /* arg setup according to flags (23=5:5:1:5:5:1:1) */ -OPCODE(KARG, BB) /* R(a) = kdict[Syms(Bx)] # todo */ -OPCODE(KARG2, BB) /* R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo */ +OPCODE(ARGARY, BS) /* R(a) = argument array (16=m5:r1:m5:d1:lv4) */ +OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1) */ +OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) # todo */ +OPCODE(KEYEND, Z) /* raise unless kdict.empty? # todo */ +OPCODE(KARG, BB) /* R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) # todo */ OPCODE(KDICT, B) /* R(a) = kdict # todo */ OPCODE(RETURN, B) /* return R(a) (normal) */ OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ OPCODE(BREAK, B) /* break R(a) */ -OPCODE(BLKPUSH, BS) /* R(a) = block (16=6:1:5:4) */ +OPCODE(BLKPUSH, BS) /* R(a) = block (16=m5:r1:m5:d1:lv4) */ OPCODE(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */ OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (Syms[b]=:+) */ OPCODE(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 3ba2324fb..070aaac51 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -420,6 +420,9 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) if (no_peephole(s)) { normal: genop_2(s, OP_MOVE, dst, src); + if (on_eval(s)) { + genop_0(s, OP_NOP); + } return; } else { @@ -453,6 +456,25 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) } } +static void +gen_return(codegen_scope *s, uint8_t op, uint16_t src) +{ + if (no_peephole(s)) { + genop_1(s, op, src); + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_MOVE && src == data.a) { + s->pc = s->lastpc; + genop_1(s, op, data.b); + } + else { + genop_1(s, op, src); + } + } +} + static void gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) { @@ -514,30 +536,28 @@ dispatch_linked(codegen_scope *s, uint16_t pos) #define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) static void -push_(codegen_scope *s) +push_n_(codegen_scope *s, int n) { - if (s->sp >= 0xffff) { + if (s->sp+n >= 0xffff) { codegen_error(s, "too complex expression"); } - s->sp++; + s->sp+=n; nregs_update; } static void -push_n_(codegen_scope *s, int n) +pop_n_(codegen_scope *s, int n) { - if (s->sp+n >= 0xffff) { - codegen_error(s, "too complex expression"); + if ((int)s->sp-n < 0) { + codegen_error(s, "stack pointer underflow"); } - s->sp+=n; - nregs_update; + s->sp-=n; } -#define push() push_(s) +#define push() push_n_(s,1) #define push_n(n) push_n_(s,n) -#define pop_(s) ((s)->sp--) -#define pop() pop_(s) -#define pop_n(n) (s->sp-=(n)) +#define pop() pop_n_(s,1) +#define pop_n(n) pop_n_(s,n) #define cursp() (s->sp) static inline int @@ -644,8 +664,12 @@ node_len(node *tree) return n; } +#define nint(x) ((int)(intptr_t)(x)) +#define nchar(x) ((char)(intptr_t)(x)) #define nsym(x) ((mrb_sym)(intptr_t)(x)) + #define lv_name(lv) nsym((lv)->car) + static int lv_idx(codegen_scope *s, mrb_sym id) { @@ -694,7 +718,7 @@ for_body(codegen_scope *s, node *tree) /* loop body */ codegen(s, tree->cdr->cdr->car, VAL); pop(); - genop_1(s, OP_RETURN, cursp()); + gen_return(s, OP_RETURN, cursp()); loop_pop(s, NOVAL); scope_finish(s); s = prev; @@ -726,32 +750,44 @@ lambda_body(codegen_scope *s, node *tree, int blk) int ma, oa, ra, pa, ka, kd, ba; int pos, i; node *n, *opt; + node *tail; + /* mandatory arguments */ ma = node_len(tree->car->car); n = tree->car->car; while (n) { n = n->cdr; } + tail = tree->car->cdr->cdr->cdr->cdr; + + /* optional arguments */ oa = node_len(tree->car->cdr->car); + /* rest argument? */ ra = tree->car->cdr->cdr->car ? 1 : 0; + /* mandatory arugments after rest argument */ pa = node_len(tree->car->cdr->cdr->cdr->car); - ka = kd = 0; - ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0; - + /* keyword arguments */ + ka = tail? node_len(tail->cdr->car) : 0; + /* keyword dictionary? */ + kd = tail && tail->cdr->cdr->car? 1 : 0; + /* block argument? */ + ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0; + if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) { codegen_error(s, "too many formal arguments"); } - a = ((mrb_aspec)(ma & 0x1f) << 18) - | ((mrb_aspec)(oa & 0x1f) << 13) - | ((ra & 1) << 12) - | ((pa & 0x1f) << 7) - | ((ka & 0x1f) << 2) - | ((kd & 1)<< 1) - | (ba & 1); - s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ - | ((ra & 1) << 5) - | (pa & 0x1f); + a = MRB_ARGS_REQ(ma) + | MRB_ARGS_OPT(oa) + | (ra? MRB_ARGS_REST() : 0) + | MRB_ARGS_POST(pa) + | MRB_ARGS_KEY(ka, kd) + | (ba? MRB_ARGS_BLOCK() : 0); + s->ainfo = (((ma+oa) & 0x3f) << 7) /* (12bits = 5:1:5:1) */ + | ((ra & 0x1) << 6) + | ((pa & 0x1f) << 1) + | (kd & 0x1); genop_W(s, OP_ENTER, a); + /* generate jump table for optional arguments initializer */ pos = new_label(s); for (i=0; i 0) { dispatch(s, pos+i*3+1); } + + if (tail) { + node *kwds = tail->cdr->car; + int kwrest = 0; + + if (tail->cdr->cdr->car) { + kwrest = 1; + } + mrb_assert(nint(tail->car) == NODE_ARGS_TAIL); + mrb_assert(node_len(tail) == 4); + + while (kwds) { + int jmpif_key_p, jmp_def_set = -1; + node *kwd = kwds->car, *def_arg = kwd->cdr->cdr->car; + mrb_sym kwd_sym = nsym(kwd->cdr->car); + + mrb_assert(nint(kwd->car) == NODE_KW_ARG); + + if (def_arg) { + genop_2(s, OP_KEY_P, cursp(), new_sym(s, kwd_sym)); + jmpif_key_p = genjmp2(s, OP_JMPIF, cursp(), 0, 0); + codegen(s, def_arg, VAL); + pop(); + gen_move(s, lv_idx(s, kwd_sym), cursp(), 0); + jmp_def_set = genjmp(s, OP_JMP, 0); + dispatch(s, jmpif_key_p); + } + genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym)); + if (jmp_def_set != -1) { + dispatch(s, jmp_def_set); + } + i++; + + kwds = kwds->cdr; + } + if (tail->cdr->car && !kwrest) { + genop_0(s, OP_KEYEND); + } + } } codegen(s, tree->cdr->car, VAL); pop(); if (s->pc > 0) { - genop_1(s, OP_RETURN, cursp()); + gen_return(s, OP_RETURN, cursp()); } if (blk) { loop_pop(s, NOVAL); @@ -798,7 +873,7 @@ scope_body(codegen_scope *s, node *tree, int val) } codegen(scope, tree->cdr, VAL); - genop_1(scope, OP_RETURN, scope->sp-1); + gen_return(scope, OP_RETURN, scope->sp-1); if (!s->iseq) { genop_0(scope, OP_STOP); } @@ -810,9 +885,6 @@ scope_body(codegen_scope *s, node *tree, int val) return s->irep->rlen - 1; } -#define nint(x) ((int)(intptr_t)(x)) -#define nchar(x) ((char)(intptr_t)(x)) - static mrb_bool nosplat(node *t) { @@ -1703,11 +1775,18 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_HASH: + case NODE_KW_HASH: { int len = 0; mrb_bool update = FALSE; while (tree) { + if (nt == NODE_KW_HASH && + nint(tree->car->car->car) == NODE_KW_REST_ARGS) { + tree = tree->cdr; + continue; + } + codegen(s, tree->car->car, val); codegen(s, tree->car->cdr, val); len++; @@ -2055,10 +2134,10 @@ codegen(codegen_scope *s, node *tree, int val) genop_1(s, OP_LOADNIL, cursp()); } if (s->loop) { - genop_1(s, OP_RETURN_BLK, cursp()); + gen_return(s, OP_RETURN_BLK, cursp()); } else { - genop_1(s, OP_RETURN, cursp()); + gen_return(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2116,7 +2195,7 @@ codegen(codegen_scope *s, node *tree, int val) else { genop_1(s, OP_LOADNIL, cursp()); } - genop_1(s, OP_RETURN, cursp()); + gen_return(s, OP_RETURN, cursp()); } if (val) push(); break; @@ -2999,7 +3078,7 @@ loop_break(codegen_scope *s, node *tree) if (!tree) { genop_1(s, OP_LOADNIL, cursp()); } - genop_1(s, OP_BREAK, cursp()); + gen_return(s, OP_BREAK, cursp()); } } } diff --git a/mrbgems/mruby-compiler/core/node.h b/mrbgems/mruby-compiler/core/node.h index 9636dd759..af71332e7 100644 --- a/mrbgems/mruby-compiler/core/node.h +++ b/mrbgems/mruby-compiler/core/node.h @@ -46,6 +46,7 @@ enum node_type { NODE_ARRAY, NODE_ZARRAY, NODE_HASH, + NODE_KW_HASH, NODE_RETURN, NODE_YIELD, NODE_LVAR, @@ -73,6 +74,9 @@ enum node_type { NODE_DREGX_ONCE, NODE_LIST, NODE_ARG, + NODE_ARGS_TAIL, + NODE_KW_ARG, + NODE_KW_REST_ARGS, NODE_ARGSCAT, NODE_ARGSPUSH, NODE_SPLAT, diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 61d94edc9..44cb28608 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -568,6 +568,13 @@ new_hash(parser_state *p, node *a) return cons((node*)NODE_HASH, a); } +/* (:kw_hash (k . v) (k . v)...) */ +static node* +new_kw_hash(parser_state *p, node *a) +{ + return cons((node*)NODE_KW_HASH, a); +} + /* (:sym . a) */ static node* new_sym(parser_state *p, mrb_sym sym) @@ -671,23 +678,61 @@ new_arg(parser_state *p, mrb_sym sym) return cons((node*)NODE_ARG, nsym(sym)); } -/* (m o r m2 b) */ +/* (m o r m2 tail) */ /* m: (a b c) */ /* o: ((a . e1) (b . e2)) */ /* r: a */ /* m2: (a b c) */ /* b: a */ static node* -new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk) +new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail) { node *n; - n = cons(m2, nsym(blk)); + n = cons(m2, tail); n = cons(nsym(rest), n); n = cons(opt, n); return cons(m, n); } +/* (:args_tail keywords rest_keywords_sym block_sym) */ +static node* +new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk) +{ + node *k; + + /* allocate register for keywords hash */ + if (kws || kwrest) { + local_add_f(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : mrb_intern_lit(p->mrb, "**")); + } + + /* allocate register for block */ + local_add_f(p, blk? blk : mrb_intern_lit(p->mrb, "&")); + + // allocate register for keywords arguments + // order is for Proc#parameters + for (k = kws; k; k = k->cdr) { + if (!k->car->cdr->cdr->car) { // allocate required keywords + local_add_f(p, sym(k->car->cdr->car)); + } + } + for (k = kws; k; k = k->cdr) { + if (k->car->cdr->cdr->car) { // allocate keywords with default + local_add_f(p, sym(k->car->cdr->car)); + } + } + + return list4((node*)NODE_ARGS_TAIL, kws, kwrest, nsym(blk)); +} + +/* (:kw_arg kw_sym def_arg) */ +static node* +new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg) +{ + mrb_assert(kw); + return list3((node*)NODE_KW_ARG, nsym(kw), def_arg); +} + /* (:block_arg . a) */ static node* new_block_arg(parser_state *p, node *a) @@ -1134,6 +1179,10 @@ heredoc_end(parser_state *p) %type heredoc words symbols %type call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */ +%type args_tail opt_args_tail f_kwarg f_kw arg_value f_kwrest +%type f_block_kwarg f_block_kw block_args_tail opt_block_args_tail +%type f_label + %token tUPLUS /* unary+ */ %token tUMINUS /* unary- */ %token tPOW /* ** */ @@ -1159,6 +1208,7 @@ heredoc_end(parser_state *p) %token tLBRACE /* { */ %token tLBRACE_ARG /* { */ %token tSTAR /* * */ +%token tDSTAR /* ** */ %token tAMPER /* & */ %token tLAMBDA /* -> */ %token tANDDOT /* &. */ @@ -1736,6 +1786,7 @@ op : '|' { $$ = intern_c('|'); } | '/' { $$ = intern_c('/'); } | '%' { $$ = intern_c('%'); } | tPOW { $$ = intern("**",2); } + | tDSTAR { $$ = intern("**",2); } | '!' { $$ = intern_c('!'); } | '~' { $$ = intern_c('~'); } | tUPLUS { $$ = intern("+@",2); } @@ -1944,11 +1995,11 @@ aref_args : none } | args comma assocs trailer { - $$ = push($1, new_hash(p, $3)); + $$ = push($1, new_kw_hash(p, $3)); } | assocs trailer { - $$ = cons(new_hash(p, $1), 0); + $$ = cons(new_kw_hash(p, $1), 0); NODE_LINENO($$, $1); } ; @@ -1984,12 +2035,12 @@ opt_call_args : none } | args comma assocs ',' { - $$ = cons(push($1, new_hash(p, $3)), 0); + $$ = cons(push($1, new_kw_hash(p, $3)), 0); NODE_LINENO($$, $1); } | assocs ',' { - $$ = cons(list1(new_hash(p, $1)), 0); + $$ = cons(list1(new_kw_hash(p, $1)), 0); NODE_LINENO($$, $1); } ; @@ -2007,12 +2058,12 @@ call_args : command } | assocs opt_block_arg { - $$ = cons(list1(new_hash(p, $1)), $2); + $$ = cons(list1(new_kw_hash(p, $1)), $2); NODE_LINENO($$, $1); } | args comma assocs opt_block_arg { - $$ = cons(push($1, new_hash(p, $3)), $4); + $$ = cons(push($1, new_kw_hash(p, $3)), $4); NODE_LINENO($$, $1); } | block_arg @@ -2451,23 +2502,51 @@ f_margs : f_marg_list } ; -block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg +block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, $1, $3, $4); + } + | f_block_kwarg opt_f_block_arg + { + $$ = new_args_tail(p, $1, 0, $2); + } + | f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, 0, $1, $2); + } + | f_block_arg + { + $$ = new_args_tail(p, 0, 0, $1); + } + ; + +opt_block_args_tail : ',' block_args_tail + { + $$ = $2; + } + | /* none */ + { + $$ = new_args_tail(p, 0, 0, 0); + } + ; + +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, $1, $3, $5, 0, $6); } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, $3, $5, $7, $8); } - | f_arg ',' f_block_optarg opt_f_block_arg + | f_arg ',' f_block_optarg opt_block_args_tail { $$ = new_args(p, $1, $3, 0, 0, $4); } - | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg + | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, $3, 0, $5, $6); } - | f_arg ',' f_rest_arg opt_f_block_arg + | f_arg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, $1, 0, $3, 0, $4); } @@ -2475,39 +2554,39 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg { $$ = new_args(p, $1, 0, 0, 0, 0); } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, $1, 0, $3, $5, $6); } - | f_arg opt_f_block_arg + | f_arg opt_block_args_tail { $$ = new_args(p, $1, 0, 0, 0, $2); } - | f_block_optarg ',' f_rest_arg opt_f_block_arg + | f_block_optarg ',' f_rest_arg opt_block_args_tail { $$ = new_args(p, 0, $1, $3, 0, $4); } - | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, $1, $3, $5, $6); } - | f_block_optarg opt_f_block_arg + | f_block_optarg opt_block_args_tail { $$ = new_args(p, 0, $1, 0, 0, $2); } - | f_block_optarg ',' f_arg opt_f_block_arg + | f_block_optarg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, $1, 0, $3, $4); } - | f_rest_arg opt_f_block_arg + | f_rest_arg opt_block_args_tail { $$ = new_args(p, 0, 0, $1, 0, $2); } - | f_rest_arg ',' f_arg opt_f_block_arg + | f_rest_arg ',' f_arg opt_block_args_tail { $$ = new_args(p, 0, 0, $1, $3, $4); } - | f_block_arg + | block_args_tail { $$ = new_args(p, 0, 0, 0, 0, $1); } @@ -3021,65 +3100,153 @@ f_arglist : '(' f_args rparen } ; -f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg +f_label : tIDENTIFIER tLABEL_TAG + ; + +arg_value : arg + ; + +f_kw : f_label arg_value + { + $$ = new_kw_arg(p, $1, $2); + } + | f_label + { + $$ = new_kw_arg(p, $1, 0); + } + ; + +f_block_kw : f_label primary_value + { + $$ = new_kw_arg(p, $1, $2); + } + | f_label + { + $$ = new_kw_arg(p, $1, 0); + } + ; + +f_block_kwarg : f_block_kw + { + $$ = list1($1); + } + | f_block_kwarg ',' f_block_kw + { + $$ = push($1, $3); + } + ; + +f_kwarg : f_kw + { + $$ = list1($1); + } + | f_kwarg ',' f_kw + { + $$ = push($1, $3); + } + ; + +kwrest_mark : tPOW + | tDSTAR + ; + +f_kwrest : kwrest_mark tIDENTIFIER + { + $$ = cons((node*)NODE_KW_REST_ARGS, nsym($2)); + } + | kwrest_mark + { + $$ = cons((node*)NODE_KW_REST_ARGS, 0); + } + ; + +args_tail : f_kwarg ',' f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, $1, $3, $4); + } + | f_kwarg opt_f_block_arg + { + $$ = new_args_tail(p, $1, 0, $2); + } + | f_kwrest opt_f_block_arg + { + $$ = new_args_tail(p, 0, $1, $2); + } + | f_block_arg + { + $$ = new_args_tail(p, 0, 0, $1); + } + ; + +opt_args_tail : ',' args_tail + { + $$ = $2; + } + | /* none */ + { + $$ = new_args_tail(p, 0, 0, 0); + } + ; + +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail { $$ = new_args(p, $1, $3, $5, 0, $6); } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, $1, $3, $5, $7, $8); } - | f_arg ',' f_optarg opt_f_block_arg + | f_arg ',' f_optarg opt_args_tail { $$ = new_args(p, $1, $3, 0, 0, $4); } - | f_arg ',' f_optarg ',' f_arg opt_f_block_arg + | f_arg ',' f_optarg ',' f_arg opt_args_tail { $$ = new_args(p, $1, $3, 0, $5, $6); } - | f_arg ',' f_rest_arg opt_f_block_arg + | f_arg ',' f_rest_arg opt_args_tail { $$ = new_args(p, $1, 0, $3, 0, $4); } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_arg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, $1, 0, $3, $5, $6); } - | f_arg opt_f_block_arg + | f_arg opt_args_tail { $$ = new_args(p, $1, 0, 0, 0, $2); } - | f_optarg ',' f_rest_arg opt_f_block_arg + | f_optarg ',' f_rest_arg opt_args_tail { $$ = new_args(p, 0, $1, $3, 0, $4); } - | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, 0, $1, $3, $5, $6); } - | f_optarg opt_f_block_arg + | f_optarg opt_args_tail { $$ = new_args(p, 0, $1, 0, 0, $2); } - | f_optarg ',' f_arg opt_f_block_arg + | f_optarg ',' f_arg opt_args_tail { $$ = new_args(p, 0, $1, 0, $3, $4); } - | f_rest_arg opt_f_block_arg + | f_rest_arg opt_args_tail { $$ = new_args(p, 0, 0, $1, 0, $2); } - | f_rest_arg ',' f_arg opt_f_block_arg + | f_rest_arg ',' f_arg opt_args_tail { $$ = new_args(p, 0, 0, $1, $3, $4); } - | f_block_arg + | args_tail { $$ = new_args(p, 0, 0, 0, 0, $1); } | /* none */ { - local_add_f(p, 0); + local_add_f(p, mrb_intern_lit(p->mrb, "&")); $$ = new_args(p, 0, 0, 0, 0, 0); } ; @@ -3189,7 +3356,7 @@ f_rest_arg : restarg_mark tIDENTIFIER } | restarg_mark { - local_add_f(p, 0); + local_add_f(p, mrb_intern_lit(p->mrb, "*")); $$ = -1; } ; @@ -3200,7 +3367,6 @@ blkarg_mark : '&' f_block_arg : blkarg_mark tIDENTIFIER { - local_add_f(p, $2); $$ = $2; } ; @@ -3211,7 +3377,6 @@ opt_f_block_arg : ',' f_block_arg } | none { - local_add_f(p, 0); $$ = 0; } ; @@ -3285,6 +3450,10 @@ assoc : arg tASSOC arg $$ = cons(new_sym(p, new_strsym(p, $1)), $3); } } + | tDSTAR arg_value + { + $$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2); + } ; operation : tIDENTIFIER @@ -3450,13 +3619,13 @@ backref_error(parser_state *p, node *n) { int c; - c = (int)(intptr_t)n->car; + c = intn(n->car); if (c == NODE_NTH_REF) { - yyerror_i(p, "can't set variable $%" MRB_PRId, (int)(intptr_t)n->cdr); + yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr)); } else if (c == NODE_BACK_REF) { - yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr); + yyerror_i(p, "can't set variable $%c", intn(n->cdr)); } else { mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); @@ -3469,7 +3638,7 @@ void_expr_error(parser_state *p, node *n) int c; if (n == NULL) return; - c = (int)(intptr_t)n->car; + c = intn(n->car); switch (c) { case NODE_BREAK: case NODE_RETURN: @@ -3508,7 +3677,7 @@ nextc(parser_state *p) if (p->pb) { node *tmp; - c = (int)(intptr_t)p->pb->car; + c = intn(p->pb->car); tmp = p->pb; p->pb = p->pb->cdr; cons_free(tmp); @@ -3557,7 +3726,7 @@ pushback(parser_state *p, int c) if (c >= 0) { p->column--; } - p->pb = cons((node*)(intptr_t)c, p->pb); + p->pb = cons(nint(c), p->pb); } static void @@ -3582,7 +3751,7 @@ peekc_n(parser_state *p, int n) c0 = nextc(p); if (c0 == -1) return c0; /* do not skip partial EOF */ if (c0 >= 0) --p->column; - list = push(list, (node*)(intptr_t)c0); + list = push(list, nint(c0)); } while(n--); if (p->pb) { p->pb = append((node*)list, p->pb); @@ -4019,11 +4188,11 @@ parse_string(parser_state *p) } else if (c == beg) { nest_level++; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + p->lex_strterm->cdr->car = nint(nest_level); } else if (c == end) { nest_level--; - p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; + p->lex_strterm->cdr->car = nint(nest_level); } else if (c == '\\') { c = nextc(p); @@ -4365,7 +4534,16 @@ parser_yylex(parser_state *p) return tOP_ASGN; } pushback(p, c); - c = tPOW; + if (IS_SPCARG(c)) { + yywarning(p, "`**' interpreted as argument prefix"); + c = tDSTAR; + } + else if (IS_BEG()) { + c = tDSTAR; + } + else { + c = tPOW; /* "**", "argument prefix" */ + } } else { if (c == '=') { @@ -5547,7 +5725,7 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt) int i = 0; if (!cxt) return; - if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return; + if (intn(p->tree->car) != NODE_SCOPE) return; n0 = n = p->tree->cdr->car; while (n) { i++; @@ -5897,6 +6075,48 @@ dump_recur(mrb_state *mrb, node *tree, int offset) } } +static void +dump_args(mrb_state *mrb, node *n, int offset) +{ + if (n->car) { + dump_prefix(n, offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(n2, offset+2); + printf("%s=\n", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, offset+3); + n2 = n2->cdr; + } + } + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(n, offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + + n = n->cdr; + if (n) { + mrb_assert(intn(n->car) == NODE_ARGS_TAIL); + mrb_parser_dump(mrb, n, offset); + } +} + #endif void @@ -5908,7 +6128,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) if (!tree) return; again: dump_prefix(tree, offset); - nodetype = (int)(intptr_t)tree->car; + nodetype = intn(tree->car); tree = tree->cdr; switch (nodetype) { case NODE_BEGIN: @@ -5968,7 +6188,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_LAMBDA: - printf("NODE_BLOCK:\n"); + printf("NODE_LAMBDA:\n"); + dump_prefix(tree, offset); goto block; case NODE_BLOCK: @@ -5976,43 +6197,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_BLOCK:\n"); tree = tree->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - if (n->cdr) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); - } + dump_args(mrb, tree->car, offset+1); } dump_prefix(tree, offset+1); printf("body:\n"); @@ -6164,7 +6349,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) dump_prefix(tree, offset+1); printf("method='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->cdr->car)), - (int)(intptr_t)tree->cdr->car); + intn(tree->cdr->car)); tree = tree->cdr->cdr->car; if (tree) { dump_prefix(tree, offset+1); @@ -6281,7 +6466,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; dump_prefix(tree, offset+1); - printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); + printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), intn(tree->car)); tree = tree->cdr; mrb_parser_dump(mrb, tree->car, offset+1); break; @@ -6363,11 +6548,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_BACK_REF: - printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree); + printf("NODE_BACK_REF: $%c\n", intn(tree)); break; case NODE_NTH_REF: - printf("NODE_NTH_REF: $%" MRB_PRId "\n", (mrb_int)(intptr_t)tree); + printf("NODE_NTH_REF: $%d\n", intn(tree)); break; case NODE_ARG: @@ -6380,7 +6565,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_INT: - printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car); + printf("NODE_INT %s base %d\n", (char*)tree->car, intn(tree->cdr->car)); break; case NODE_FLOAT: @@ -6393,7 +6578,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_STR: - printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, intn(tree->cdr)); break; case NODE_DSTR: @@ -6402,7 +6587,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) break; case NODE_XSTR: - printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr); + printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, intn(tree->cdr)); break; case NODE_DXSTR: @@ -6431,7 +6616,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_SYM: printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)), - (int)(intptr_t)tree); + intn(tree)); break; case NODE_SELF: @@ -6547,43 +6732,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) } tree = tree->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - if (n->cdr) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr))); - } + dump_args(mrb, tree->car, offset); } mrb_parser_dump(mrb, tree->cdr->car, offset+1); break; @@ -6596,44 +6745,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); tree = tree->cdr->cdr; if (tree->car) { - node *n = tree->car; - - if (n->car) { - dump_prefix(n, offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(n2, offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - mrb_parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(n, offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(n, offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); - } + dump_args(mrb, tree->car, offset+1); } tree = tree->cdr; mrb_parser_dump(mrb, tree->car, offset+1); @@ -6649,18 +6761,35 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); break; - case NODE_LITERAL_DELIM: - printf("NODE_LITERAL_DELIM\n"); + case NODE_ARGS_TAIL: + printf("NODE_ARGS_TAIL:\n"); + { + node *kws = tree->car; + + while (kws) { + mrb_parser_dump(mrb, kws->car, offset+1); + kws = kws->cdr; + } + } + tree = tree->cdr; + if (tree->car) { + mrb_assert(intn(tree->car->car) == NODE_KW_REST_ARGS); + mrb_parser_dump(mrb, tree->car, offset+1); + } + tree = tree->cdr; + if (tree->car) { + dump_prefix(tree, offset+1); + printf("block='%s'\n", mrb_sym2name(mrb, sym(tree->car))); + } break; - case NODE_SYMBOLS: - printf("NODE_SYMBOLS:\n"); - dump_recur(mrb, tree, offset+1); + case NODE_KW_ARG: + printf("NODE_KW_ARG %s\n", mrb_sym2name(mrb, sym(tree->car))); + mrb_parser_dump(mrb, tree->cdr->car, offset + 1); break; - case NODE_WORDS: - printf("NODE_SYMBOLS:\n"); - dump_recur(mrb, tree, offset+1); + case NODE_KW_REST_ARGS: + printf("NODE_KW_REST_ARGS %s\n", mrb_sym2name(mrb, sym(tree))); break; default: diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c index 3887091d3..b31dee04c 100644 --- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c +++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -57,7 +57,7 @@ os_count_objects(mrb_state *mrb, mrb_value self) hash = mrb_hash_new(mrb); } - if (!mrb_test(mrb_hash_empty_p(mrb, hash))) { + if (!mrb_hash_empty_p(mrb, hash)) { mrb_hash_clear(mrb, hash); } diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 323529dcc..9ce6c1831 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -149,7 +149,15 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) a = mrb_ary_new(mrb); mrb_ary_push(mrb, a, sname); if (i < max && irep->lv[i].name) { - mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name)); + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_ary_push(mrb, a, mrb_symbol_value(sym)); + break; + } } mrb_ary_push(mrb, parameters, a); } diff --git a/src/codedump.c b/src/codedump.c index 22cbc59eb..dc0e0e548 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -78,6 +78,16 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); + if (irep->lv) { + int i; + + printf("local variable names:\n"); + for (i = 1; i < irep->nlocals; ++i) { + char const *n = mrb_sym2name(mrb, irep->lv[i - 1].name); + printf(" R%d:%s\n", irep->lv[i - 1].r, n? n : ""); + } + } + pc = irep->iseq; pcend = pc + irep->ilen; while (pc < pcend) { @@ -246,10 +256,11 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("OP_SUPER\tR%d\t%d\n", a, b); break; CASE(OP_ARGARY, BS): - printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", a, - (b>>10)&0x3f, - (b>>9)&0x1, - (b>>4)&0x1f, + printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a, + (b>>11)&0x3f, + (b>>10)&0x1, + (b>>5)&0x1f, + (b>>4)&0x1, (b>>0)&0xf); print_lv_a(mrb, irep, a); break; @@ -263,32 +274,39 @@ codedump(mrb_state *mrb, mrb_irep *irep) (a>>1)&0x1, a & 0x1); break; - CASE(OP_KARG, BB): - printf("OP_KARG\tR(%d)\tK(%d)\n", a, b); + CASE(OP_KEY_P, BB): + printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; - CASE(OP_KARG2, BB): - printf("OP_KARG2\tR(%d)\tK(%d)\n", a, b); + CASE(OP_KEYEND, Z): + printf("OP_KEYEND\n"); + break; + CASE(OP_KARG, BB): + printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); + print_lv_a(mrb, irep, a); break; CASE(OP_KDICT, B): - printf("OP_KDICt\tR(%d)\n", a); + printf("OP_KDICT\tR%d\t\t", a); + print_lv_a(mrb, irep, a); break; CASE(OP_RETURN, B): - printf("OP_RETURN\tR%d", a); + printf("OP_RETURN\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_RETURN_BLK, B): - printf("OP_RETURN_BLK\tR%d", a); + printf("OP_RETURN_BLK\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_BREAK, B): - printf("OP_BREAK\tR%d", a); + printf("OP_BREAK\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_BLKPUSH, BS): - printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", a, - (b>>10)&0x3f, - (b>>9)&0x1, - (b>>4)&0x1f, + printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a, + (b>>11)&0x3f, + (b>>10)&0x1, + (b>>5)&0x1f, + (b>>4)&0x1, (b>>0)&0xf); print_lv_a(mrb, irep, a); break; diff --git a/src/hash.c b/src/hash.c index db9d1d9c8..0dce81677 100644 --- a/src/hash.c +++ b/src/hash.c @@ -208,6 +208,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) return vret; } +void +mrb_hash_check_kdict(mrb_state *mrb, mrb_value self) +{ + khash_t(ht) *orig_h; + khiter_t k; + int nosym = FALSE; + + orig_h = RHASH_TBL(self); + if (!orig_h || kh_size(orig_h) == 0) return; + for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { + if (kh_exist(orig_h, k)) { + mrb_value key = kh_key(orig_h, k); + + if (!mrb_symbol_p(key)) nosym = TRUE; + } + } + if (nosym) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys"); + } +} + +MRB_API mrb_value +mrb_hash_dup(mrb_state *mrb, mrb_value self) +{ + struct RHash* copy; + khash_t(ht) *orig_h; + + orig_h = RHASH_TBL(self); + copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + copy->ht = kh_init(ht, mrb); + + if (orig_h && kh_size(orig_h) > 0) { + int ai = mrb_gc_arena_save(mrb); + khash_t(ht) *copy_h = copy->ht; + khiter_t k, copy_k; + + for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { + if (kh_exist(orig_h, k)) { + copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k))); + mrb_gc_arena_restore(mrb, ai); + kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v; + kh_val(copy_h, copy_k).n = kh_size(copy_h)-1; + } + } + } + return mrb_obj_value(copy); +} + MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { @@ -716,13 +764,21 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self) * {}.empty? #=> true * */ -MRB_API mrb_value +MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self) { khash_t(ht) *h = RHASH_TBL(self); - if (h) return mrb_bool_value(kh_size(h) == 0); - return mrb_true_value(); + if (h) return kh_size(h) == 0; + return TRUE; +} + +static mrb_value +mrb_hash_empty_m(mrb_state *mrb, mrb_value self) +{ + if (mrb_hash_empty_p(mrb, self)) + return mrb_true_value(); + return mrb_false_value(); } /* 15.2.13.4.29 (x)*/ @@ -833,21 +889,29 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) * */ -static mrb_value -mrb_hash_has_key(mrb_state *mrb, mrb_value hash) +MRB_API mrb_bool +mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) { - mrb_value key; khash_t(ht) *h; khiter_t k; - mrb_get_args(mrb, "o", &key); - h = RHASH_TBL(hash); if (h) { k = kh_get(ht, mrb, h, key); - return mrb_bool_value(k != kh_end(h)); + return k != kh_end(h); } - return mrb_false_value(); + return FALSE; +} + +static mrb_value +mrb_hash_has_key(mrb_state *mrb, mrb_value hash) +{ + mrb_value key; + mrb_bool key_p; + + mrb_get_args(mrb, "o", &key); + key_p = mrb_hash_key_p(mrb, hash, key); + return mrb_bool_value(key_p); } /* 15.2.13.4.14 */ @@ -904,7 +968,7 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,MRB_ARGS_NONE()); /* 15.2.13.4.7 */ mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,MRB_ARGS_REQ(1)); /* 15.2.13.4.7 */ mrb_define_method(mrb, h, "__delete", mrb_hash_delete, MRB_ARGS_REQ(1)); /* core of 15.2.13.4.8 */ - mrb_define_method(mrb, h, "empty?", mrb_hash_empty_p, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ + mrb_define_method(mrb, h, "empty?", mrb_hash_empty_m, MRB_ARGS_NONE()); /* 15.2.13.4.12 */ mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */ mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */ mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */ diff --git a/src/kernel.c b/src/kernel.c index 155868eaa..42e9ca6a4 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1194,7 +1194,15 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) if (!irep->lv) break; for (i = 0; i + 1 < irep->nlocals; ++i) { if (irep->lv[i].name) { - mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); + break; + } } } if (!MRB_PROC_ENV_P(proc)) break; diff --git a/src/vm.c b/src/vm.c index b50f1ee9f..8aeb68fc2 100644 --- a/src/vm.c +++ b/src/vm.c @@ -969,6 +969,8 @@ check_target_class(mrb_state *mrb) return TRUE; } +void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); + MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { @@ -1639,9 +1641,10 @@ RETRY_TRY_BLOCK: } CASE(OP_ARGARY, BS) { - int m1 = (b>>10)&0x3f; - int r = (b>>9)&0x1; - int m2 = (b>>4)&0x1f; + int m1 = (b>>11)&0x3f; + int r = (b>>10)&0x1; + int m2 = (b>>5)&0x1f; + int kd = (b>>4)&0x1; int lv = (b>>0)&0xf; mrb_value *stack; @@ -1657,12 +1660,12 @@ RETRY_TRY_BLOCK: else { struct REnv *e = uvenv(mrb, lv-1); if (!e) goto L_NOSUPER; - if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) + if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+kd+1) goto L_NOSUPER; stack = e->stack + 1; } if (r == 0) { - regs[a] = mrb_ary_new_from_values(mrb, m1+m2, stack); + regs[a] = mrb_ary_new_from_values(mrb, m1+m2+kd, stack); } else { mrb_value *pp = NULL; @@ -1675,7 +1678,7 @@ RETRY_TRY_BLOCK: pp = ARY_PTR(ary); len = (int)ARY_LEN(ary); } - regs[a] = mrb_ary_new_capa(mrb, m1+len+m2); + regs[a] = mrb_ary_new_capa(mrb, m1+len+m2+kd); rest = mrb_ary_ptr(regs[a]); if (m1 > 0) { stack_copy(ARY_PTR(rest), stack, m1); @@ -1686,7 +1689,10 @@ RETRY_TRY_BLOCK: if (m2 > 0) { stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2); } - ARY_SET_LEN(rest, m1+len+m2); + if (kd) { + stack_copy(ARY_PTR(rest)+m1+len+m2, stack+m1+m2+1, kd); + } + ARY_SET_LEN(rest, m1+len+m2+kd); } regs[a+1] = stack[m1+r+m2]; mrb_gc_arena_restore(mrb, ai); @@ -1698,74 +1704,114 @@ RETRY_TRY_BLOCK: int o = MRB_ASPEC_OPT(a); int r = MRB_ASPEC_REST(a); int m2 = MRB_ASPEC_POST(a); + int kd = (MRB_ASPEC_KEY(a) > 0 || MRB_ASPEC_KDICT(a))? 1 : 0; /* unused - int k = MRB_ASPEC_KEY(a); - int kd = MRB_ASPEC_KDICT(a); int b = MRB_ASPEC_BLOCK(a); */ int argc = mrb->c->ci->argc; mrb_value *argv = regs+1; - mrb_value *argv0 = argv; - int len = m1 + o + r + m2; + mrb_value * const argv0 = argv; + int const len = m1 + o + r + m2; + int const blk_pos = len + kd + 1; mrb_value *blk = &argv[argc < 0 ? 1 : argc]; + mrb_value kdict; + int kargs = kd; + /* arguments is passed with Array */ if (argc < 0) { struct RArray *ary = mrb_ary_ptr(regs[1]); argv = ARY_PTR(ary); argc = (int)ARY_LEN(ary); mrb_gc_protect(mrb, regs[1]); } + + /* strict argument check */ if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) { - if (argc >= 0) { - if (argc < m1 + m2 || (r == 0 && argc > len)) { + if (argc >= 0 && !(argc <= 1 && kd)) { + if (argc < m1 + m2 + kd || (r == 0 && argc > len + kd)) { argnum_error(mrb, m1+m2); goto L_RAISE; } } } + /* extract first argument array to arguments */ else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) { mrb_gc_protect(mrb, argv[0]); argc = (int)RARRAY_LEN(argv[0]); argv = RARRAY_PTR(argv[0]); } + + if (kd) { + /* check last arguments is hash if method takes keyword arguments */ + if (argc == m1+m2) { + kdict = mrb_hash_new(mrb); + kargs = 0; + } + else { + if (!mrb_hash_p(argv[argc - 1])) { + if (r) { + kdict = mrb_hash_new(mrb); + kargs = 0; + } + else { + mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } + } + else { + kdict = argv[argc-1]; + } + mrb_hash_check_kdict(mrb, kdict); + if (MRB_ASPEC_KEY(a) > 0) { + kdict = mrb_hash_dup(mrb, kdict); + } + } + } + + /* no rest arguments */ if (argc < len) { int mlen = m2; if (argc < m1+m2) { - if (m1 < argc) - mlen = argc - m1; - else - mlen = 0; + mlen = m1 < argc ? argc - m1 : 0; } - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; + SET_NIL_VALUE(regs[argc+1]); + /* copy mandatory and optional arguments */ if (argv0 != argv) { value_move(®s[1], argv, argc-mlen); /* m1 + o */ } if (argc < m1) { stack_clear(®s[argc+1], m1-argc); } + /* copy post mandatory arguments */ if (mlen) { value_move(®s[len-m2+1], &argv[argc-mlen], mlen); } if (mlen < m2) { stack_clear(®s[len-m2+mlen+1], m2-mlen); } + /* initalize rest arguments with empty Array */ if (r) { regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } - if (o > 0 && argc >= m1+m2) - pc += (argc - m1 - m2)*3; + /* skip initailizer of passed arguments */ + if (o > 0 && argc-kargs >= m1+m2) + pc += (argc - kargs - m1 - m2)*3; } else { int rnum = 0; if (argv0 != argv) { - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; value_move(®s[1], argv, m1+o); } if (r) { mrb_value ary; - rnum = argc-m1-o-m2; + rnum = argc-m1-o-m2-kargs; ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); regs[m1+o+1] = ary; } @@ -1775,29 +1821,60 @@ RETRY_TRY_BLOCK: } } if (argv0 == argv) { - regs[len+1] = *blk; /* move block */ + regs[blk_pos] = *blk; /* move block */ + if (kd) regs[len + 1] = kdict; } pc += o*3; } - mrb->c->ci->argc = len; + + /* format arguments for generated code */ + mrb->c->ci->argc = len + kd; + /* clear local (but non-argument) variables */ - if (irep->nlocals-len-2 > 0) { - stack_clear(®s[len+2], irep->nlocals-len-2); + if (irep->nlocals-blk_pos-1 > 0) { + stack_clear(®s[blk_pos+1], irep->nlocals-blk_pos-1); } JUMP; } CASE(OP_KARG, BB) { - /* not implemented yet */ + mrb_value k = mrb_symbol_value(syms[b]); + mrb_value kdict = regs[mrb->c->ci->argc]; + + if (!mrb_hash_key_p(mrb, kdict, k)) { + mrb_value str = mrb_format(mrb, "missing keyword: %S", k); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } + regs[a] = mrb_hash_get(mrb, kdict, k); + mrb_hash_delete_key(mrb, kdict, k); NEXT; } - CASE(OP_KARG2, BB) { - /* not implemented yet */ + + CASE(OP_KEY_P, BB) { + mrb_value k = mrb_symbol_value(syms[b]); + mrb_value kdict = regs[mrb->c->ci->argc]; + mrb_bool key_p = mrb_hash_key_p(mrb, kdict, k); + + regs[a] = mrb_bool_value(key_p); + NEXT; + } + + CASE(OP_KEYEND, Z) { + mrb_value kdict = regs[mrb->c->ci->argc]; + + if (mrb_hash_p(kdict) && !mrb_hash_empty_p(mrb, kdict)) { + mrb_value keys = mrb_hash_keys(mrb, kdict); + mrb_value key1 = RARRAY_PTR(keys)[0]; + mrb_value str = mrb_format(mrb, "unknown keyword: %S", key1); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; + } NEXT; } CASE(OP_KDICT, B) { - /* not implemented yet */ + regs[a] = regs[mrb->c->ci->argc]; NEXT; } @@ -2064,9 +2141,10 @@ RETRY_TRY_BLOCK: } CASE(OP_BLKPUSH, BS) { - int m1 = (b>>10)&0x3f; - int r = (b>>9)&0x1; - int m2 = (b>>4)&0x1f; + int m1 = (b>>11)&0x3f; + int r = (b>>10)&0x1; + int m2 = (b>>5)&0x1f; + int kd = (b>>4)&0x1; int lv = (b>>0)&0xf; mrb_value *stack; @@ -2084,7 +2162,7 @@ RETRY_TRY_BLOCK: localjump_error(mrb, LOCALJUMP_ERROR_YIELD); goto L_RAISE; } - regs[a] = stack[m1+r+m2]; + regs[a] = stack[m1+r+m2+kd]; NEXT; } diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 299394557..6392509ec 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -403,6 +403,9 @@ assert('External command execution.') do assert_equal 'test dynamic `', t assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results + results = [] + assert_equal 'test sym test sym test', `test #{:sym} test #{:sym} test` + alias_method sym, :old_cmd end true @@ -466,3 +469,183 @@ this is a comment that has extra after =begin and =end with tabs after it =end xxxxxxxxxxxxxxxxxxxxxxxxxx assert_equal(line + 4, __LINE__) end + +assert 'keyword arguments' do + def m(a, b:) [a, b] end + assert_equal [1, 2], m(1, b: 2) + assert_raise(ArgumentError) { m b: 1 } + assert_raise(ArgumentError) { m 1 } + + def m(a:) a end + assert_equal 1, m(a: 1) + assert_raise(ArgumentError) { m } + assert_raise(ArgumentError) { m 'a' => 1, a: 1 } + h = { a: 1 } + assert_equal 1, m(h) + assert_equal({ a: 1 }, h) + + def m(a: 1) a end + assert_equal 1, m + assert_equal 2, m(a: 2) + assert_raise(ArgumentError) { m 1 } + + def m(**) end + assert_nil m + assert_nil m a: 1, b: 2 + assert_raise(ArgumentError) { m 2 } + + def m(a, **) a end + assert_equal 1, m(1) + assert_equal 1, m(1, a: 2, b: 3) + assert_equal({ 'a' => 1, b: 2 }, m('a' => 1, b: 2)) + + def m(a, **k) [a, k] end + assert_equal [1, {}], m(1) + assert_equal [1, {a: 2, b: 3}], m(1, a: 2, b: 3) + assert_equal [{'a' => 1, b: 2}, {}], m('a' => 1, b: 2) + + def m(a=1, **) a end + assert_equal 1, m + assert_equal 2, m(2, a: 1, b: 0) + assert_raise(ArgumentError) { m('a' => 1, a: 2) } + + def m(a=1, **k) [a, k] end + assert_equal [1, {}], m + assert_equal [2, {a: 1, b: 2}], m(2, a: 1, b: 2) + assert_equal [{a: 1}, {b: 2}], m({a: 1}, {b: 2}) + + def m(*, a:) a end + assert_equal 1, m(a: 1) + assert_equal 3, m(1, 2, a: 3) + assert_raise(ArgumentError) { m('a' => 1, a: 2) } + + def m(*a, b:) [a, b] end + assert_equal [[], 1], m(b: 1) + assert_equal [[1, 2], 3], m(1, 2, b: 3) + assert_raise(ArgumentError) { m('a' => 1, b: 2) } + + def m(*a, b: 1) [a, b] end + assert_equal [[], 1], m + assert_equal [[1, 2, 3], 4], m(1, 2, 3, b: 4) + assert_raise(ArgumentError) { m('a' => 1, b: 2) } + + def m(*, **) end + assert_nil m() + assert_nil m(a: 1, b: 2) + assert_nil m(1, 2, 3, a: 4, b: 5) + + def m(*a, **) a end + assert_equal [], m() + assert_equal [1, 2, 3], m(1, 2, 3, a: 4, b: 5) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal [1], m(1, **{a: 2}) + + def m(*, **k) k end + assert_equal({}, m()) + assert_equal({a: 4, b: 5}, m(1, 2, 3, a: 4, b: 5)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + + def m(a = nil, b = nil, **k) [a, k] end + assert_equal [nil, {}], m() + assert_equal([nil, {a: 1}], m(a: 1)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal([{"a" => 1}, {a: 1}], m({ "a" => 1 }, a: 1)) + assert_equal([{a: 1}, {}], m({a: 1}, {})) + assert_equal([nil, {}], m({})) + + def m(*a, **k) [a, k] end + assert_equal([[], {}], m()) + assert_equal([[1], {}], m(1)) + assert_equal([[], {a: 1, b: 2}], m(a: 1, b: 2)) + assert_equal([[1, 2, 3], {a: 2}], m(1, 2, 3, a: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_raise(ArgumentError) { m("a" => 1) } + assert_equal([[], {a: 1}], m(a: 1)) + assert_raise(ArgumentError) { m("a" => 1, a: 1) } + assert_equal([[{"a" => 1}], {a: 1}], m({ "a" => 1 }, a: 1)) + assert_equal([[{a: 1}], {}], m({a: 1}, {})) + assert_raise(ArgumentError) { m({a: 1}, {"a" => 1}) } + + def m(a:, b:) [a, b] end + assert_equal([1, 2], m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, b: 1) [a, b] end + assert_equal([1, 1], m(a: 1)) + assert_equal([1, 2], m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, **) a end + assert_equal(1, m(a: 1)) + assert_equal(1, m(a: 1, b: 2)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + + def m(a:, **k) [a, k] end + assert_equal([1, {}], m(a: 1)) + assert_equal([1, {b: 2, c: 3}], m(a: 1, b: 2, c: 3)) + assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) } + +=begin + def m(a:, &b) [a, b] end + assert_equal([1, nil], m(a: 1)) + assert_equal([1, l], m(a: 1, &(l = ->{}))) +=end + + def m(a: 1, b:) [a, b] end + assert_equal([1, 0], m(b: 0)) + assert_equal([3, 2], m(b: 2, a: 3)) + assert_raise(ArgumentError) { m a: 1 } + + def m(a: def m(a: 1) a end, b:) + [a, b] + end + assert_equal([2, 3], m(a: 2, b: 3)) + assert_equal([:m, 1], m(b: 1)) + # Note the default value of a: in the original method. + assert_equal(1, m()) + + def m(a: 1, b: 2) [a, b] end + assert_equal([1, 2], m()) + assert_equal([4, 3], m(b: 3, a: 4)) + + def m(a: 1, **) a end + assert_equal(1, m()) + assert_equal(2, m(a: 2, b: 1)) + + def m(a: 1, **k) [a, k] end + assert_equal([1, {b: 2, c: 3}], m(b: 2, c: 3)) + + def m(a:, **) yield end + assert_raise(ArgumentError) { m { :blk } } + assert_equal :blk, m(a: 1){ :blk } + + def m(a:, **k, &b) [b.call, k] end + assert_raise(ArgumentError) { m { :blk } } + assert_equal [:blk, {b: 2}], m(a: 1, b: 2){ :blk } + + def m(**k, &b) [k, b] end + assert_equal([{ a: 1, b: 2}, nil], m(a: 1, b: 2)) + assert_equal :blk, m{ :blk }[1].call + + def m(hsh = {}) hsh end + assert_equal({ a: 1, b: 2 }, m(a: 1, b: 2)) + assert_equal({ a: 1, 'b' => 2 }, m(a: 1, 'b' => 2)) + + def m(hsh) hsh end + assert_equal({ a: 1, b: 2 }, m(a: 1, b: 2)) + assert_equal({ a: 1, 'b' => 2 }, m(a: 1, 'b' => 2)) + +=begin + def m(a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l) + [a, b, c, d, e, f, g, h, k, l] + end + result = m(9, 8, 7, 6, f: 5, g: 4, h: 3, &(l = ->{})) + assert_equal([9, 8, [7], [], 6, 5, 4, 3, {}, l], result) + + def m a, b=1, *c, d, e:, f: 2, g:, **k, &l + [a, b, c, d, e, f, g, k, l] + end + result = m(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{})) + assert_equal([1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l], result) +=end +end -- cgit v1.2.3 From 53e2723faede0e6f9959bd3316f4dd1e84b69609 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 03:14:42 +0900 Subject: Fixed a small bug in keyword argument parsing. def m(a=1,**k) p [a,k] end m(a: 1) --- src/vm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 8aeb68fc2..8fe7c69b0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1770,7 +1770,7 @@ RETRY_TRY_BLOCK: } /* no rest arguments */ - if (argc < len) { + if (argc-kargs < len) { int mlen = m2; if (argc < m1+m2) { mlen = m1 < argc ? argc - m1 : 0; @@ -1778,7 +1778,6 @@ RETRY_TRY_BLOCK: regs[blk_pos] = *blk; /* move block */ if (kd) regs[len + 1] = kdict; - SET_NIL_VALUE(regs[argc+1]); /* copy mandatory and optional arguments */ if (argv0 != argv) { value_move(®s[1], argv, argc-mlen); /* m1 + o */ @@ -1798,7 +1797,7 @@ RETRY_TRY_BLOCK: regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } /* skip initailizer of passed arguments */ - if (o > 0 && argc-kargs >= m1+m2) + if (o > 0 && argc-kargs > m1+m2) pc += (argc - kargs - m1 - m2)*3; } else { -- cgit v1.2.3 From 43173e129965d776791fc643aba9f4c5244d8466 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 03:20:00 +0900 Subject: Removed unused instruction: `OP_KDICT`. --- include/mruby/ops.h | 1 - src/codedump.c | 4 ---- src/vm.c | 5 ----- 3 files changed, 10 deletions(-) (limited to 'src') diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 9675d6158..b8fc89d43 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -66,7 +66,6 @@ OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5: OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) # todo */ OPCODE(KEYEND, Z) /* raise unless kdict.empty? # todo */ OPCODE(KARG, BB) /* R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) # todo */ -OPCODE(KDICT, B) /* R(a) = kdict # todo */ OPCODE(RETURN, B) /* return R(a) (normal) */ OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ OPCODE(BREAK, B) /* break R(a) */ diff --git a/src/codedump.c b/src/codedump.c index dc0e0e548..842d40bdf 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -285,10 +285,6 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; - CASE(OP_KDICT, B): - printf("OP_KDICT\tR%d\t\t", a); - print_lv_a(mrb, irep, a); - break; CASE(OP_RETURN, B): printf("OP_RETURN\tR%d\t\t", a); print_lv_a(mrb, irep, a); diff --git a/src/vm.c b/src/vm.c index 8fe7c69b0..d47b4c7fc 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1872,11 +1872,6 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_KDICT, B) { - regs[a] = regs[mrb->c->ci->argc]; - NEXT; - } - CASE(OP_BREAK, B) { c = OP_R_BREAK; goto L_RETURN; -- cgit v1.2.3 From fd086833ff6673ab11e6ecea573851593263ae6a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 31 Jul 2018 16:48:50 +0900 Subject: Reorganize flags values for classes; fix #3975 Renamed flag macro names as well: `MRB_FLAG_IS_FROZEN` -> `MRB_FL_OBJ_FROZEN` `MRB_FLAG_IS_PREPENDED` -> `MRB_FL_CLASS_IS_PREPENDED` `MRB_FLAG_IS_ORIGIN` -> `MRB_FL_CLASS_IS_ORIGIN` `MRB_FLAG_IS_INHERITED` -> `MRB_FL_CLASS_IS_INHERITED` --- include/mruby/class.h | 20 +++++++++++++------- include/mruby/object.h | 9 ++++----- src/class.c | 24 ++++++++++++------------ src/gc.c | 4 ++-- src/kernel.c | 10 +++++----- 5 files changed, 36 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/include/mruby/class.h b/include/mruby/class.h index 706a4d37c..ddcbd5f98 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -53,19 +53,25 @@ mrb_class(mrb_state *mrb, mrb_value v) } } -/* TODO: figure out where to put user flags */ -/* flags bits >= 18 is reserved */ -#define MRB_FLAG_IS_PREPENDED (1 << 19) -#define MRB_FLAG_IS_ORIGIN (1 << 20) +/* flags: + 20: frozen + 19: is_prepended + 18: is_origin + 17: is_inherited (used by method cache) + 16: unused + 0-15: instance type +*/ +#define MRB_FL_CLASS_IS_PREPENDED (1 << 19) +#define MRB_FL_CLASS_IS_ORIGIN (1 << 18) #define MRB_CLASS_ORIGIN(c) do {\ - if (c->flags & MRB_FLAG_IS_PREPENDED) {\ + if (c->flags & MRB_FL_CLASS_IS_PREPENDED) {\ c = c->super;\ - while (!(c->flags & MRB_FLAG_IS_ORIGIN)) {\ + while (!(c->flags & MRB_FL_CLASS_IS_ORIGIN)) {\ c = c->super;\ }\ }\ } while (0) -#define MRB_FLAG_IS_INHERITED (1 << 21) +#define MRB_FL_CLASS_IS_INHERITED (1 << 17) #define MRB_INSTANCE_TT_MASK (0xFF) #define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) #define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK) diff --git a/include/mruby/object.h b/include/mruby/object.h index 4f2134ae2..25584a1d4 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -22,11 +22,10 @@ struct RBasic { }; #define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) -/* flags bits >= 18 is reserved */ -#define MRB_FLAG_IS_FROZEN (1 << 18) -#define MRB_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN) -#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN) -#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN) +#define MRB_FL_OBJ_IS_FROZEN (1 << 20) +#define MRB_FROZEN_P(o) ((o)->flags & MRB_FL_OBJ_IS_FROZEN) +#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FL_OBJ_IS_FROZEN) +#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FL_OBJ_IS_FROZEN) struct RObject { MRB_OBJECT_HEADER; diff --git a/src/class.c b/src/class.c index 076280f3f..660dc3b3d 100644 --- a/src/class.c +++ b/src/class.c @@ -93,7 +93,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); - sc->flags |= MRB_FLAG_IS_INHERITED; + sc->flags |= MRB_FL_CLASS_IS_INHERITED; sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { @@ -275,7 +275,7 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) if (!super) super = mrb->object_class; - super->flags |= MRB_FLAG_IS_INHERITED; + super->flags |= MRB_FL_CLASS_IS_INHERITED; s = mrb_obj_value(super); mc_clear_by_class(mrb, klass); mid = mrb_intern_lit(mrb, "inherited"); @@ -1061,7 +1061,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru while (m) { int superclass_seen = 0; - if (m->flags & MRB_FLAG_IS_PREPENDED) + if (m->flags & MRB_FL_CLASS_IS_PREPENDED) goto skip; if (klass_mt && klass_mt == m->mt) @@ -1084,7 +1084,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru } ic = include_class_new(mrb, m, ins_pos->super); - m->flags |= MRB_FLAG_IS_INHERITED; + m->flags |= MRB_FL_CLASS_IS_INHERITED; ins_pos->super = ic; mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); mc_clear_by_class(mrb, ins_pos); @@ -1111,15 +1111,15 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; - if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); - origin->flags |= MRB_FLAG_IS_ORIGIN | MRB_FLAG_IS_INHERITED; + origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; origin->super = c->super; c->super = origin; origin->mt = c->mt; c->mt = kh_init(mt, mrb); mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); - c->flags |= MRB_FLAG_IS_PREPENDED; + c->flags |= MRB_FL_CLASS_IS_PREPENDED; } changed = include_module_at(mrb, c, c, m, 0); if (changed < 0) { @@ -1196,7 +1196,7 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { + else if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -1365,9 +1365,9 @@ mc_clear_by_class(mrb_state *mrb, struct RClass *c) struct mrb_cache_entry *mc = mrb->cache; int i; - if (c->flags & MRB_FLAG_IS_INHERITED) { + if (c->flags & MRB_FL_CLASS_IS_INHERITED) { mc_clear_all(mrb); - c->flags &= ~MRB_FLAG_IS_INHERITED; + c->flags &= ~MRB_FL_CLASS_IS_INHERITED; return; } for (i=0; icache; int i; - if (c->flags & MRB_FLAG_IS_INHERITED) { + if (c->flags & MRB_FL_CLASS_IS_INHERITED) { mc_clear_all(mrb); - c->flags &= ~MRB_FLAG_IS_INHERITED; + c->flags &= ~MRB_FL_CLASS_IS_INHERITED; return; } for (i=0; isuper); } @@ -761,7 +761,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) mrb_gc_free_iv(mrb, (struct RObject*)obj); break; case MRB_TT_ICLASS: - if (MRB_FLAG_TEST(obj, MRB_FLAG_IS_ORIGIN)) + if (MRB_FLAG_TEST(obj, MRB_FL_CLASS_IS_ORIGIN)) mrb_gc_free_mt(mrb, (struct RClass*)obj); break; case MRB_TT_ENV: diff --git a/src/kernel.c b/src/kernel.c index 42e9ca6a4..9986b0222 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -252,18 +252,18 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) struct RClass *sc = mrb_class_ptr(src); /* if the origin is not the same as the class, then the origin and the current class need to be copied */ - if (sc->flags & MRB_FLAG_IS_PREPENDED) { + if (sc->flags & MRB_FL_CLASS_IS_PREPENDED) { struct RClass *c0 = sc->super; struct RClass *c1 = dc; /* copy prepended iclasses */ - while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) { + while (!(c0->flags & MRB_FL_CLASS_IS_ORIGIN)) { c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); c1 = c1->super; c0 = c0->super; } c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); - c1->super->flags |= MRB_FLAG_IS_ORIGIN; + c1->super->flags |= MRB_FL_CLASS_IS_ORIGIN; } if (sc->mt) { dc->mt = kh_copy(mt, mrb, sc->mt); @@ -348,7 +348,7 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)p->c); clone = mrb_obj_value(p); init_copy(mrb, clone, self); - p->flags |= mrb_obj_ptr(self)->flags & MRB_FLAG_IS_FROZEN; + p->flags |= mrb_obj_ptr(self)->flags & MRB_FL_OBJ_IS_FROZEN; return clone; } @@ -706,7 +706,7 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl struct RClass* oldklass; khash_t(st)* set = kh_init(st, mrb); - if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) { + if (!recur && (klass->flags & MRB_FL_CLASS_IS_PREPENDED)) { MRB_CLASS_ORIGIN(klass); prepended = TRUE; } -- cgit v1.2.3 From 91c08d7631e0495bf29d8b8910cca2073f8b192b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 13:18:32 +0900 Subject: Remove `nregs` member from `mrb_callinfo`. This means reducing one word per a call frame. --- include/mruby.h | 1 - mrbgems/mruby-fiber/src/fiber.c | 1 - src/gc.c | 32 +++++++++++--- src/vm.c | 97 ++++++++++++++++++++++++----------------- 4 files changed, 83 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 7cbc690b3..12ddb95b3 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -123,7 +123,6 @@ typedef struct { mrb_sym mid; struct RProc *proc; mrb_value *stackent; - uint16_t nregs; uint16_t ridx; uint16_t epos; struct REnv *env; diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index 27b74dba5..17ce77c5d 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -127,7 +127,6 @@ fiber_init(mrb_state *mrb, mrb_value self) ci->proc = p; mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p); ci->pc = p->body.irep->iseq; - ci->nregs = p->body.irep->nregs; ci[1] = ci[0]; c->ci++; /* push dummy callinfo */ diff --git a/src/gc.c b/src/gc.c index c52641959..33d83f28e 100644 --- a/src/gc.c +++ b/src/gc.c @@ -548,21 +548,39 @@ add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) gc->gray_list = obj; } +static int +ci_nregs(mrb_callinfo *ci) +{ + struct RProc *p = ci->proc; + int n = 0; + + if (!p) { + if (ci->argc < 0) return 3; + return ci->argc+2; + } + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + n = p->body.irep->nregs; + } + if (ci->argc < 0) { + if (n < 3) n = 3; /* self + args + blk */ + } + if (ci->argc > n) { + n = ci->argc + 2; /* self + blk */ + } + return n; +} + static void mark_context_stack(mrb_state *mrb, struct mrb_context *c) { size_t i; size_t e; mrb_value nil; - mrb_int nregs; if (c->stack == NULL) return; e = c->stack - c->stbase; if (c->ci) { - nregs = c->ci->argc + 2; - if (c->ci->nregs > nregs) - nregs = c->ci->nregs; - e += nregs; + e += ci_nregs(c->ci); } if (c->stbase + e > c->stend) e = c->stend - c->stbase; for (i=0; istack - c->stbase; - if (c->ci) i += c->ci->nregs; + if (c->ci) { + i += ci_nregs(c->ci); + } if (c->stbase + i > c->stend) i = c->stend - c->stbase; children += i; diff --git a/src/vm.c b/src/vm.c index d47b4c7fc..91c617a83 100644 --- a/src/vm.c +++ b/src/vm.c @@ -356,7 +356,6 @@ ecall(mrb_state *mrb) ci->acc = CI_ACC_SKIP; ci->argc = 0; ci->proc = p; - ci->nregs = p->body.irep->nregs; ci->target_class = MRB_PROC_TARGET_CLASS(p); env = MRB_PROC_ENV(p); mrb_assert(env); @@ -396,6 +395,30 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...) return mrb_funcall_argv(mrb, self, mid, argc, argv); } +static int +ci_nregs(mrb_callinfo *ci) +{ + struct RProc *p; + int n = 0; + + if (!ci) return 3; + p = ci->proc; + if (!p) { + if (ci->argc < 0) return 3; + return ci->argc+2; + } + if (!MRB_PROC_CFUNC_P(p) && p->body.irep) { + n = p->body.irep->nregs; + } + if (ci->argc < 0) { + if (n < 3) n = 3; /* self + args + blk */ + } + if (ci->argc > n) { + n = ci->argc + 2; /* self + blk */ + } + return n; +} + MRB_API mrb_value mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk) { @@ -426,13 +449,12 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_t m; struct RClass *c; mrb_callinfo *ci; - int n; + int n = ci_nregs(mrb->c->ci); ptrdiff_t voff = -1; if (!mrb->c->stack) { stack_init(mrb); } - n = mrb->c->ci->nregs; if (argc < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc)); } @@ -463,22 +485,22 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc voff = argv - mrb->c->stbase; } if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (int)(argc + 2); - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, argc + 2); } else if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - mrb_stack_extend(mrb, ci->nregs+2); + + mrb_stack_extend(mrb, 3); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; } else { struct RProc *p = MRB_METHOD_PROC(m); + ci->proc = p; if (argc < 0) argc = 1; - ci->nregs = (int)(p->body.irep->nregs + argc); - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, p->body.irep->nregs + argc); } if (voff >= 0) { argv = mrb->c->stbase + voff; @@ -520,26 +542,25 @@ mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; - int keep; + int keep, nregs; mrb->c->stack[0] = self; ci->proc = p; if (MRB_PROC_CFUNC_P(p)) { return MRB_PROC_CFUNC(p)(mrb, self); } - ci->nregs = p->body.irep->nregs; + nregs = p->body.irep->nregs; if (ci->argc < 0) keep = 3; else keep = ci->argc + 2; - if (ci->nregs < keep) { + if (nregs < keep) { mrb_stack_extend(mrb, keep); } else { - mrb_stack_extend(mrb, ci->nregs); - stack_clear(mrb->c->stack+keep, ci->nregs-keep); + mrb_stack_extend(mrb, nregs); + stack_clear(mrb->c->stack+keep, nregs-keep); } ci = cipush(mrb); - ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -618,6 +639,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) { struct RProc *p; mrb_callinfo *ci; + int nregs; if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); @@ -639,13 +661,12 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) mrb->c->stack[2] = mrb_nil_value(); return MRB_PROC_CFUNC(p)(mrb, self); } - ci->nregs = p->body.irep->nregs; - mrb_stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs); + nregs = p->body.irep->nregs; + mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; mrb->c->stack[2] = mrb_nil_value(); ci = cipush(mrb); - ci->nregs = 0; ci->target_class = 0; ci->pc = p->body.irep->iseq; ci->stackent = mrb->c->stack; @@ -728,13 +749,15 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value struct RProc *p; mrb_sym mid = mrb->c->ci->mid; mrb_callinfo *ci; - int n = mrb->c->ci->nregs; mrb_value val; + int n; if (mrb_nil_p(b)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } - if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + ci = mrb->c->ci; + n = ci_nregs(ci); + if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = mrb_proc_ptr(b); @@ -745,9 +768,9 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value ci->argc = (int)argc; ci->target_class = c; ci->acc = CI_ACC_SKIP; + n = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; mrb->c->stack = mrb->c->stack + n; - ci->nregs = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, n); mrb->c->stack[0] = self; if (argc > 0) { @@ -1008,7 +1031,6 @@ RETRY_TRY_BLOCK: } mrb->jmp = &c_jmp; mrb->c->ci->proc = proc; - mrb->c->ci->nregs = irep->nregs; #define regs (mrb->c->stack) INIT_DISPATCH { @@ -1296,6 +1318,8 @@ RETRY_TRY_BLOCK: if (a > (int)mrb->c->eidx - epos) a = mrb->c->eidx - epos; for (n=0; nnregs; + proc = mrb->c->ensure[epos+n]; mrb->c->ensure[epos+n] = NULL; if (proc == NULL) continue; @@ -1305,12 +1329,11 @@ RETRY_TRY_BLOCK: ci->argc = 0; ci->proc = proc; ci->stackent = mrb->c->stack; - ci->nregs = irep->nregs; ci->target_class = target_class; ci->pc = pc; - ci->acc = ci[-1].nregs; + ci->acc = nregs; mrb->c->stack += ci->acc; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, irep->nregs); regs[0] = self; pc = irep->iseq; } @@ -1350,7 +1373,7 @@ RETRY_TRY_BLOCK: mrb_value recv, blk; mrb_sym mid = syms[b]; - mrb_assert(bidx < ci->nregs); + mrb_assert(bidx < irep->nregs); recv = regs[a]; blk = regs[bidx]; @@ -1396,7 +1419,6 @@ RETRY_TRY_BLOCK: mrb->c->stack += a; if (MRB_METHOD_CFUNC_P(m)) { - ci->nregs = (argc < 0) ? 3 : c+2; if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); @@ -1442,8 +1464,7 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; JUMP; } @@ -1498,8 +1519,7 @@ RETRY_TRY_BLOCK: } pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, ci->nregs); + mrb_stack_extend(mrb, irep->nregs); if (ci->argc < 0) { if (irep->nregs > 3) { stack_clear(regs+3, irep->nregs-3); @@ -1526,7 +1546,7 @@ RETRY_TRY_BLOCK: mrb_sym mid = ci->mid; struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc); - mrb_assert(bidx < ci->nregs); + mrb_assert(bidx < irep->nregs); if (mid == 0 || !target_class) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); @@ -1572,7 +1592,7 @@ RETRY_TRY_BLOCK: } mid = missing; if (argc >= 0) { - if (a+2 >= ci->nregs) { + if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); } regs[a+1] = mrb_ary_new_from_values(mrb, b, regs+a+1); @@ -1596,7 +1616,7 @@ RETRY_TRY_BLOCK: if (MRB_METHOD_CFUNC_P(m)) { mrb_value v; - ci->nregs = (argc < 0) ? 3 : b+2; + if (MRB_METHOD_PROC_P(m)) { ci->proc = MRB_METHOD_PROC(m); } @@ -1633,8 +1653,7 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs); + mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; JUMP; } @@ -2795,9 +2814,8 @@ RETRY_TRY_BLOCK: irep = p->body.irep; pool = irep->pool; syms = irep->syms; - ci->nregs = irep->nregs; - mrb_stack_extend(mrb, ci->nregs); - stack_clear(regs+1, ci->nregs-1); + mrb_stack_extend(mrb, irep->nregs); + stack_clear(regs+1, irep->nregs-1); pc = irep->iseq; JUMP; } @@ -2946,7 +2964,6 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta } ci = cipush(mrb); ci->mid = 0; - ci->nregs = 1; /* protect the receiver */ ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_vm_run(mrb, proc, self, stack_keep); -- cgit v1.2.3 From 6681e22c71c55ae09d802dad17296a1ebe49bb13 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 16:50:44 +0900 Subject: Simply use `snprintf` instead of custom `fmt_fp`, Unless `MRB_DISABLE_STDIO` is set. `snprintf` is used anyway if mruby is configured to use `stdio`. This change reduces 8KB of program size on the Linux box. --- src/fmt_fp.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/fmt_fp.c b/src/fmt_fp.c index f8a8f7904..783cc6c02 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -1,3 +1,5 @@ +#ifndef MRB_WITHOUT_FLOAT +#ifdef MRB_DISABLE_STDIO /* Most code in this file originates from musl (src/stdio/vfprintf.c) @@ -36,7 +38,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include -#ifndef MRB_WITHOUT_FLOAT struct fmt_args { mrb_state *mrb; mrb_value str; @@ -371,4 +372,17 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) } return f.str; } +#else /* MRB_DISABLE_STDIO */ +#include +#include + +mrb_value +mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) +{ + char buf[24]; + + snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); + return mrb_str_new_cstr(mrb, buf); +} +#endif /* MRB_DISABLE_STDIO */ #endif -- cgit v1.2.3 From f3564a405ee766797be191cedd90aa3ab8b5e5c5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 1 Aug 2018 21:55:11 +0900 Subject: Small refactoring of `flodivmod()`. --- src/numeric.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 4e5fc394e..c3e7d77a3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -220,29 +220,40 @@ flo_mul(mrb_state *mrb, mrb_value x) } static void -flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp) +flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp) { - mrb_float div; - mrb_float mod; + double div, mod; + if (isnan(y)) { + /* y is NaN so all results are NaN */ + div = mod = y; + goto exit; + } if (y == 0.0) { - if (x > 0.0) div = INFINITY; - else if (x < 0.0) div = -INFINITY; - else div = NAN; /* x == 0.0 */ + if (x == 0) div = NAN; + else if (x > 0.0) div = INFINITY; + else div = -INFINITY; /* x < 0.0 */ mod = NAN; + goto exit; + } + if ((x == 0.0) || (isinf(y) && !isinf(x))) { + mod = x; } else { mod = fmod(x, y); - if (isinf(x) && isfinite(y)) - div = x; - else - div = (x - mod) / y; - if (y*mod < 0) { - mod += y; - div -= 1.0; - } } - + if (isinf(x) && !isinf(y)) { + div = x; + } + else { + div = (x - mod) / y; + if (modp && divp) div = round(div); + } + if (y*mod < 0) { + mod += y; + div -= 1.0; + } + exit: if (modp) *modp = mod; if (divp) *divp = div; } -- cgit v1.2.3 From c88fd32713e980abe5613ae06f46d9ceaa0c063b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 Aug 2018 21:08:50 +0900 Subject: Revert 04dbbff. Use segment list for instance variable again to reduce memory. --- src/variable.c | 335 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 205 insertions(+), 130 deletions(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index de36efac6..cbfdb2f2d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -12,152 +12,243 @@ typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); -#include - -#ifndef MRB_IVHASH_INIT_SIZE -#define MRB_IVHASH_INIT_SIZE KHASH_MIN_SIZE +#ifndef MRB_IV_SEGMENT_SIZE +#define MRB_IV_SEGMENT_SIZE 4 #endif -KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE) -KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal) +typedef struct segment { + mrb_sym key[MRB_IV_SEGMENT_SIZE]; + mrb_value val[MRB_IV_SEGMENT_SIZE]; + struct segment *next; +} segment; /* Instance variable table structure */ typedef struct iv_tbl { - khash_t(iv) h; + segment *rootseg; + size_t size; + size_t last_len; } iv_tbl; -/* - * Creates the instance variable table. - * - * Parameters - * mrb - * Returns - * the instance variable table. - */ +/* Creates the instance variable table. */ static iv_tbl* iv_new(mrb_state *mrb) { - return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE); + iv_tbl *t; + + t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl)); + t->size = 0; + t->rootseg = NULL; + t->last_len = 0; + + return t; } -/* - * Set the value for the symbol in the instance variable table. - * - * Parameters - * mrb - * t the instance variable table to be set in. - * sym the symbol to be used as the key. - * val the value to be set. - */ +/* Set the value for the symbol in the instance variable table. */ static void iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) { - khash_t(iv) *h = &t->h; - khiter_t k; + segment *seg; + segment *prev = NULL; + segment *matched_seg = NULL; + size_t matched_idx = 0; + size_t i; - k = kh_put(iv, mrb, h, sym); - kh_value(h, k) = val; + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->key[i] = sym; + seg->val[i] = val; + t->last_len = i+1; + t->size++; + return; + } + if (!matched_seg && key == 0) { + matched_seg = seg; + matched_idx = i; + } + else if (key == sym) { + seg->val[i] = val; + return; + } + } + prev = seg; + seg = seg->next; + } + + /* Not found */ + t->size++; + if (matched_seg) { + matched_seg->key[matched_idx] = sym; + matched_seg->val[matched_idx] = val; + return; + } + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); + if (!seg) return; + seg->next = NULL; + seg->key[0] = sym; + seg->val[0] = val; + t->last_len = 1; + if (prev) { + prev->next = seg; + } + else { + t->rootseg = seg; + } } -/* - * Get a value for a symbol from the instance variable table. - * - * Parameters - * mrb - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receives the value if the specified symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Get a value for a symbol from the instance variable table. */ static mrb_bool iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { - khash_t(iv) *h = &t->h; - khiter_t k; + segment *seg; + size_t i; - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - if (vp) *vp = kh_value(h, k); - return TRUE; + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key == sym) { + if (vp) *vp = seg->val[i]; + return TRUE; + } + } + seg = seg->next; } return FALSE; } -/* - * Deletes the value for the symbol from the instance variable table. - * - * Parameters - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receive the deleted value if the symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Deletes the value for the symbol from the instance variable table. */ static mrb_bool iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { + segment *seg; + size_t i; + if (t == NULL) return FALSE; - else { - khash_t(iv) *h = &t->h; - khiter_t k; - - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - mrb_value val = kh_value(h, k); - kh_del(iv, mrb, h, k); - if (vp) *vp = val; - return TRUE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key == sym) { + t->size--; + seg->key[i] = 0; + if (vp) *vp = seg->val[i]; + return TRUE; + } } + seg = seg->next; } return FALSE; } +/* Iterates over the instance variable table. */ static mrb_bool iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) { - if (t == NULL) { - return TRUE; - } - else { - khash_t(iv) *h = &t->h; - khiter_t k; - int n; + segment *seg; + size_t i; + int n; + + if (t == NULL) return TRUE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); + /* no value in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (key != 0) { + n =(*func)(mrb, key, seg->val[i], p); if (n > 0) return FALSE; if (n < 0) { - kh_del(iv, mrb, h, k); + t->size--; + seg->key[i] = 0; } } } + seg = seg->next; } return TRUE; } +/* Get the size of the instance variable table. */ static size_t iv_size(mrb_state *mrb, iv_tbl *t) { - if (t) { - return kh_size(&t->h); + segment *seg; + size_t size = 0; + + if (t == NULL) return 0; + if (t->size > 0) return t->size; + seg = t->rootseg; + while (seg) { + if (seg->next == NULL) { + size += t->last_len; + return size; + } + seg = seg->next; + size += MRB_IV_SEGMENT_SIZE; } + /* empty iv_tbl */ return 0; } +/* Copy the instance variable table. */ static iv_tbl* iv_copy(mrb_state *mrb, iv_tbl *t) { - return (iv_tbl*)kh_copy(iv, mrb, &t->h); + segment *seg; + iv_tbl *t2; + + size_t i; + + seg = t->rootseg; + t2 = iv_new(mrb); + + while (seg != NULL) { + for (i=0; ikey[i]; + mrb_value val = seg->val[i]; + + if ((seg->next == NULL) && (i >= t->last_len)) { + return t2; + } + iv_put(mrb, t2, key, val); + } + seg = seg->next; + } + return t2; } +/* Free memory of the instance variable table. */ static void iv_free(mrb_state *mrb, iv_tbl *t) { - kh_destroy(iv, mrb, &t->h); + segment *seg; + + seg = t->rootseg; + while (seg) { + segment *p = seg; + seg = seg->next; + mrb_free(mrb, p); + } + mrb_free(mrb, t); } static int @@ -170,9 +261,7 @@ iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) static void mark_tbl(mrb_state *mrb, iv_tbl *t) { - if (t) { - iv_foreach(mrb, t, iv_mark_i, 0); - } + iv_foreach(mrb, t, iv_mark_i, 0); } void @@ -258,16 +347,17 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t = obj->iv; + iv_tbl *t; if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } - if (!t) { - t = obj->iv = iv_new(mrb); + if (!obj->iv) { + obj->iv = iv_new(mrb); } - mrb_write_barrier(mrb, (struct RBasic*)obj); + t = obj->iv; iv_put(mrb, t, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)obj); } MRB_API void @@ -401,7 +491,7 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; - if (t && iv_del(mrb, t, sym, &val)) { + if (iv_del(mrb, t, sym, &val)) { return val; } } @@ -460,7 +550,7 @@ mrb_obj_instance_variables(mrb_state *mrb, mrb_value self) mrb_value ary; ary = mrb_ary_new(mrb); - if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) { + if (obj_iv_p(self)) { iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary); } return ary; @@ -506,9 +596,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) ary = mrb_ary_new(mrb); c = mrb_class_ptr(mod); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, cv_i, &ary); - } + iv_foreach(mrb, c->iv, cv_i, &ary); c = c->super; } return ary; @@ -563,14 +651,12 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) struct RClass * cls = c; while (c) { - if (c->iv) { - iv_tbl *t = c->iv; + iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) { - mrb_write_barrier(mrb, (struct RBasic*)c); - iv_put(mrb, t, sym, v); - return; - } + if (iv_get(mrb, t, sym, NULL)) { + iv_put(mrb, t, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)c); + return; } c = c->super; } @@ -599,8 +685,8 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c->iv = iv_new(mrb); } - mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, c->iv, sym, v); + mrb_write_barrier(mrb, (struct RBasic*)c); } MRB_API void @@ -613,10 +699,8 @@ MRB_API mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { - if (c->iv) { - iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) return TRUE; - } + iv_tbl *t = c->iv; + if (iv_get(mrb, t, sym, NULL)) return TRUE; c = c->super; } @@ -672,7 +756,7 @@ const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool top) L_RETRY: while (c) { - if (c->iv && (top || c != oclass || base == oclass)) { + if (top || c != oclass || base == oclass) { if (iv_get(mrb, c->iv, sym, &v)) return v; } @@ -703,22 +787,25 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) struct RProc *proc; c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); - if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + if (iv_get(mrb, c->iv, sym, &v)) { return v; } c2 = c; while (c2 && c2->tt == MRB_TT_SCLASS) { mrb_value klass; - klass = mrb_obj_iv_get(mrb, (struct RObject *)c2, - mrb_intern_lit(mrb, "__attached__")); + + if (!iv_get(mrb, c2->iv, mrb_intern_lit(mrb, "__attached__"), &klass)) { + c2 = NULL; + break; + } c2 = mrb_class_ptr(klass); } - if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2; + if (c2 && (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)) c = c2; mrb_assert(!MRB_PROC_CFUNC_P(mrb->c->ci->proc)); proc = mrb->c->ci->proc; while (proc) { c2 = MRB_PROC_TARGET_CLASS(proc); - if (c2 && c2->iv && iv_get(mrb, c2->iv, sym, &v)) { + if (c2 && iv_get(mrb, c2->iv, sym, &v)) { return v; } proc = proc->upper; @@ -796,9 +883,7 @@ mrb_mod_constants(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "|b", &inherit); ary = mrb_ary_new(mrb); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, const_i, &ary); - } + iv_foreach(mrb, c->iv, const_i, &ary); if (!inherit) break; c = c->super; if (c == mrb->object_class) break; @@ -811,9 +896,6 @@ mrb_gv_get(mrb_state *mrb, mrb_sym sym) { mrb_value v; - if (!mrb->globals) { - return mrb_nil_value(); - } if (iv_get(mrb, mrb->globals, sym, &v)) return v; return mrb_nil_value(); @@ -825,20 +907,15 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) iv_tbl *t; if (!mrb->globals) { - t = mrb->globals = iv_new(mrb); - } - else { - t = mrb->globals; + mrb->globals = iv_new(mrb); } + t = mrb->globals; iv_put(mrb, t, sym, v); } MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym) { - if (!mrb->globals) { - return; - } iv_del(mrb, mrb->globals, sym, NULL); } @@ -870,9 +947,7 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) size_t i; char buf[3]; - if (t) { - iv_foreach(mrb, t, gv_i, &ary); - } + iv_foreach(mrb, t, gv_i, &ary); buf[0] = '$'; buf[2] = 0; for (i = 1; i <= 9; ++i) { @@ -892,7 +967,7 @@ mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, tmp = klass; retry: while (tmp) { - if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) { + if (iv_get(mrb, tmp->iv, id, NULL)) { return TRUE; } if (!recurse && (klass != mrb->object_class)) break; -- cgit v1.2.3 From 5e469d2b924a70617be75b0c765da73497d3927c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 2 Aug 2018 21:14:52 +0900 Subject: Remove utility functions: `mrb_vm_iv_{get,set}`. --- include/mruby/variable.h | 2 -- src/variable.c | 14 -------------- src/vm.c | 3 +-- 3 files changed, 1 insertion(+), 18 deletions(-) (limited to 'src') diff --git a/include/mruby/variable.h b/include/mruby/variable.h index 5fef83faf..a4394fbd3 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -31,8 +31,6 @@ struct global_entry { mrb_value mrb_vm_special_get(mrb_state*, mrb_sym); void mrb_vm_special_set(mrb_state*, mrb_sym, mrb_value); -mrb_value mrb_vm_iv_get(mrb_state*, mrb_sym); -void mrb_vm_iv_set(mrb_state*, mrb_sym, mrb_value); mrb_value mrb_vm_cv_get(mrb_state*, mrb_sym); void mrb_vm_cv_set(mrb_state*, mrb_sym, mrb_value); mrb_value mrb_vm_const_get(mrb_state*, mrb_sym); diff --git a/src/variable.c b/src/variable.c index cbfdb2f2d..6612c186f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -498,20 +498,6 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_undef_value(); } -mrb_value -mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym) -{ - /* get self */ - return mrb_iv_get(mrb, mrb->c->stack[0], sym); -} - -void -mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) -{ - /* get self */ - mrb_iv_set(mrb, mrb->c->stack[0], sym, v); -} - static int iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { diff --git a/src/vm.c b/src/vm.c index 91c617a83..b8feb52db 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1131,8 +1131,7 @@ RETRY_TRY_BLOCK: } CASE(OP_GETIV, BB) { - mrb_value val = mrb_vm_iv_get(mrb, syms[b]); - regs[a] = val; + regs[a] = mrb_vm_iv_get(mrb, syms[b]); NEXT; } -- cgit v1.2.3 From 9409a2ff6d7c1467900278898d97c95dfe9ea229 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 3 Aug 2018 15:03:09 +0900 Subject: Rename ambiguous function names. `mrb_iv_p` -> `mrb_iv_name_sym_p` `mrb_iv_check` -> `mrb_iv_name_sym_check` --- include/mruby/variable.h | 4 ++-- src/class.c | 4 ++-- src/kernel.c | 8 ++++---- src/variable.c | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/include/mruby/variable.h b/include/mruby/variable.h index a4394fbd3..a0fbca1f9 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -40,8 +40,8 @@ MRB_API void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value); MRB_API mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_const_remove(mrb_state*, mrb_value, mrb_sym); -MRB_API mrb_bool mrb_iv_p(mrb_state *mrb, mrb_sym sym); -MRB_API void mrb_iv_check(mrb_state *mrb, mrb_sym sym); +MRB_API mrb_bool mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym sym); +MRB_API void mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym sym); MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym); MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); MRB_API mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym); diff --git a/src/class.c b/src/class.c index 660dc3b3d..37bc39c75 100644 --- a/src/class.c +++ b/src/class.c @@ -1480,7 +1480,7 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) mrb_str_cat_lit(mrb, str, "@"); mrb_str_cat_str(mrb, str, name); sym = mrb_intern_str(mrb, str); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); name = mrb_symbol_value(sym); p = mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name); MRB_METHOD_FROM_PROC(m, p); @@ -1525,7 +1525,7 @@ mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod) mrb_str_cat_lit(mrb, str, "@"); mrb_str_cat_str(mrb, str, name); sym = mrb_intern_str(mrb, str); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); attr = mrb_symbol_value(sym); /* prepare method name (name=) */ diff --git a/src/kernel.c b/src/kernel.c index 9986b0222..fed64e9b0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -575,7 +575,7 @@ mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) mrb_sym sym; mrb_get_args(mrb, "n", &sym); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); } @@ -605,7 +605,7 @@ mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) mrb_sym iv_name; mrb_get_args(mrb, "n", &iv_name); - mrb_iv_check(mrb, iv_name); + mrb_iv_name_sym_check(mrb, iv_name); return mrb_iv_get(mrb, self, iv_name); } @@ -636,7 +636,7 @@ mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) mrb_value val; mrb_get_args(mrb, "no", &iv_name, &val); - mrb_iv_check(mrb, iv_name); + mrb_iv_name_sym_check(mrb, iv_name); mrb_iv_set(mrb, self, iv_name, val); return val; } @@ -951,7 +951,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) mrb_value val; mrb_get_args(mrb, "n", &sym); - mrb_iv_check(mrb, sym); + mrb_iv_name_sym_check(mrb, sym); val = mrb_iv_remove(mrb, self, sym); if (mrb_undef_p(val)) { mrb_name_error(mrb, sym, "instance variable %S not defined", mrb_sym2str(mrb, sym)); diff --git a/src/variable.c b/src/variable.c index 6612c186f..e753f8d29 100644 --- a/src/variable.c +++ b/src/variable.c @@ -393,7 +393,7 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) #define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) MRB_API mrb_bool -mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) { const char *s; mrb_int i, len; @@ -409,9 +409,9 @@ mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) } MRB_API void -mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name) { - if (!mrb_iv_p(mrb, iv_name)) { + if (!mrb_iv_name_sym_p(mrb, iv_name)) { mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); } } -- cgit v1.2.3 From 821135e2df838a2088ffca501403c08b21d9a8cf Mon Sep 17 00:00:00 2001 From: pyama86 Date: Mon, 6 Aug 2018 18:15:00 +0900 Subject: irep is released when Fiber is terminated --- src/gc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 33d83f28e..9858e45fc 100644 --- a/src/gc.c +++ b/src/gc.c @@ -965,9 +965,11 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) size_t i; mrb_callinfo *ci; - if (!c) break; + if (!c || c->status == MRB_FIBER_TERMINATED) break; + /* mark stack */ i = c->stack - c->stbase; + if (c->ci) { i += ci_nregs(c->ci); } -- cgit v1.2.3 From eeb6d5658d9e29ad24f211a3236eb02abcdb136c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 May 2018 15:19:06 +0900 Subject: New bytecode implementation of mruby VM. --- mrbgems/mruby-compiler/core/codegen.c | 100 ++++++++++++++++++++++++++++++++++ src/vm.c | 16 +++++- 2 files changed, 113 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index b8caba3a0..8e72abda2 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -445,8 +445,108 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) break; default: goto normal; +======= +struct mrb_insn_data { + uint8_t insn; + uint16_t a; + uint16_t b; + uint8_t c; +}; + +struct mrb_insn_data +mrb_decode_insn(codegen_scope *s, mrb_code *pc) +{ + struct mrb_insn_data data = { 0 }; + mrb_code insn = READ_B(); + uint16_t a = 0; + uint16_t b = 0; + uint8_t c = 0; + + switch (insn) { +#define FETCH_Z() /* empty */ +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; +#include "mruby/ops.h" +#undef OPCODE + } + switch (insn) { + case OP_EXT1: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT2: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT3: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + default: + break; + } + data.insn = insn; + data.a = a; + data.b = b; + data.c = c; + return data; +} + +struct mrb_insn_data +mrb_last_insn(codegen_scope *s) +{ + if (s->pc == s->lastpc) { + struct mrb_insn_data data; + + data.insn = OP_NOP; + return data; + } + return mrb_decode_insn(s, &s->iseq[s->lastpc]); +} + +static mrb_bool +no_peephole(codegen_scope *s) +{ + return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; +} + +static uint16_t +genjmp(codegen_scope *s, mrb_code i, uint16_t pc) +{ + uint16_t pos; + + s->lastpc = s->pc; + gen_B(s, i); + pos = s->pc; + gen_S(s, pc); + return pos; +} + +static uint16_t +genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) +{ + uint16_t pos; + + if (!no_peephole(s) && !val) { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_MOVE && data.a == a) { + s->pc = s->lastpc; + a = data.b; } } + return genop(s, i); } static void diff --git a/src/vm.c b/src/vm.c index b8feb52db..d206f9675 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1069,6 +1069,16 @@ RETRY_TRY_BLOCK: NEXT; } + CASE(OP_LOADI, BB) { + SET_INT_VALUE(regs[a], b); + NEXT; + } + + CASE(OP_LOADINEG, BB) { + SET_INT_VALUE(regs[a], -b); + NEXT; + } + CASE(OP_LOADI__1,B) goto L_LOADI; CASE(OP_LOADI_0,B) goto L_LOADI; CASE(OP_LOADI_1,B) goto L_LOADI; @@ -1131,12 +1141,12 @@ RETRY_TRY_BLOCK: } CASE(OP_GETIV, BB) { - regs[a] = mrb_vm_iv_get(mrb, syms[b]); + regs[a] = mrb_iv_get(mrb, regs[0], syms[b]); NEXT; } CASE(OP_SETIV, BB) { - mrb_vm_iv_set(mrb, syms[b], regs[a]); + mrb_iv_set(mrb, regs[0], syms[b], regs[a]); NEXT; } @@ -2470,7 +2480,7 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i)); + SET_FLOAT_VALUE(mrb, regs[a], x - c); } #else mrb_float(regs_a[0]) -= c; -- cgit v1.2.3 From b7e56e9d20f25b472a7c4e798771f08de2db5bc2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 Aug 2018 22:29:28 +0900 Subject: Add bytecode support for `MRB_WORD_BOXING`. --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index d206f9675..5ba98ae55 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2480,7 +2480,7 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x - c); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)c); } #else mrb_float(regs_a[0]) -= c; -- cgit v1.2.3 From 3554fc54de68e2cf92121147df071b57b50663b1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 09:08:16 +0900 Subject: Add a new function `mrb_hash_merge()`. --- include/mruby/hash.h | 10 ++++++++++ src/hash.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) (limited to 'src') diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 9a3812850..2026c8e0d 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -174,6 +174,16 @@ MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); */ MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash); +/* + * Merges two hashes. The first hash will be modified by the + * second hash. + * + * @param mrb The mruby state reference. + * @param hash1 The target hash. + * @param hash2 Updating hash + */ +MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2); + /* declaration of struct kh_ht */ /* be careful when you touch the internal */ typedef struct { diff --git a/src/hash.c b/src/hash.c index 0dce81677..122f5b5d5 100644 --- a/src/hash.c +++ b/src/hash.c @@ -951,6 +951,39 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash) return mrb_false_value(); } +MRB_API void +mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) +{ + khash_t(ht) *h1; + khash_t(ht) *h2; + khiter_t k; + + mrb_hash_modify(mrb, hash1); + hash2 = mrb_check_hash_type(mrb, hash2); + h1 = RHASH_TBL(hash1); + h2 = RHASH_TBL(hash2); + + if (!h1) { + RHASH_TBL(hash1) = kh_copy(ht, mrb, h2); + return; + } + for (k = kh_begin(h2); k != kh_end(h2); k++) { + khiter_t k1; + int r; + + if (!kh_exist(h2, k)) continue; + k1 = kh_put2(ht, mrb, h1, kh_key(h2, k), &r); + kh_value(h1, k1).v = kh_value(h2,k).v; + if (r != 0) { + /* expand */ + kh_key(h1, k1) = kh_key(h2, k); + kh_value(h1, k1).n = kh_size(h1)-1; + } + } + mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1)); + return; +} + void mrb_init_hash(mrb_state *mrb) { -- cgit v1.2.3 From 306732e02da5f0d47f44033ec1a3af1a77c5f418 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 09:09:49 +0900 Subject: Fixed a bug in `OP_HASHADD`. --- src/vm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 5ba98ae55..8332158f7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2704,9 +2704,8 @@ RETRY_TRY_BLOCK: int i; int lim = a+b*2+1; - for (i=a+1; i Date: Sat, 25 Aug 2018 09:10:37 +0900 Subject: Hash splat `**` should not be ignored. Implemented by adding `OP_HASHCAT` that merges hashes. --- include/mruby/ops.h | 1 + mrbgems/mruby-compiler/core/codegen.c | 37 ++++++++++++++++++++++++++--------- src/codedump.c | 6 +++++- src/vm.c | 5 +++++ 4 files changed, 39 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/mruby/ops.h b/include/mruby/ops.h index b8fc89d43..f23bb1b0b 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -94,6 +94,7 @@ OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */ OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */ OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b)) */ OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b)) */ +OPCODE(HASHCAT, B) /* R(a) = hash_cat(R(a),R(a+1)) */ OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */ OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */ OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 8e72abda2..bf5cc14b0 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1874,15 +1874,32 @@ codegen(codegen_scope *s, node *tree, int val) mrb_bool update = FALSE; while (tree) { - if (nt == NODE_KW_HASH && - nint(tree->car->car->car) == NODE_KW_REST_ARGS) { - tree = tree->cdr; - continue; + if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) { + if (len > 0) { + pop_n(len*2); + if (!update) { + genop_2(s, OP_HASH, cursp(), len); + } + else { + pop(); + genop_2(s, OP_HASHADD, cursp(), len); + } + push(); + } + codegen(s, tree->car->cdr, VAL); + if (len > 0) { + pop(); pop(); + genop_1(s, OP_HASHCAT, cursp()); + push(); + } + update = TRUE; + len = 0; + } + else { + codegen(s, tree->car->car, VAL); + codegen(s, tree->car->cdr, VAL); + len++; } - - codegen(s, tree->car->car, val); - codegen(s, tree->car->cdr, val); - len++; tree = tree->cdr; if (val && len == 255) { pop_n(len*2); @@ -1905,7 +1922,9 @@ codegen(codegen_scope *s, node *tree, int val) } else { pop(); - genop_2(s, OP_HASHADD, cursp(), len); + if (len > 0) { + genop_2(s, OP_HASHADD, cursp(), len); + } } push(); } diff --git a/src/codedump.c b/src/codedump.c index 842d40bdf..9174ebe3d 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -416,7 +416,11 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_HASHADD, BB): - printf("OP_HASHADD\tR%d\t%d", a, b); + printf("OP_HASHADD\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); + break; + CASE(OP_HASHCAT, B): + printf("OP_HASHCAT\tR%d\t", a); print_lv_a(mrb, irep, a); break; diff --git a/src/vm.c b/src/vm.c index 8332158f7..b47469ebf 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2710,6 +2710,11 @@ RETRY_TRY_BLOCK: mrb_gc_arena_restore(mrb, ai); NEXT; } + CASE(OP_HASHCAT, B) { + mrb_hash_merge(mrb, regs[a], regs[a+1]); + mrb_gc_arena_restore(mrb, ai); + NEXT; + } CASE(OP_LAMBDA, BB) c = OP_L_LAMBDA; -- cgit v1.2.3 From d79dbd92f9104712c6cf41ab3c029dec318a757d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 09:49:20 +0900 Subject: fixup! New bytecode implementation of mruby VM. --- mrbgems/mruby-compiler/core/codegen.c | 100 ---------------------------------- src/vm.c | 10 ---- 2 files changed, 110 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index bf5cc14b0..075945b3b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -445,108 +445,8 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) break; default: goto normal; -======= -struct mrb_insn_data { - uint8_t insn; - uint16_t a; - uint16_t b; - uint8_t c; -}; - -struct mrb_insn_data -mrb_decode_insn(codegen_scope *s, mrb_code *pc) -{ - struct mrb_insn_data data = { 0 }; - mrb_code insn = READ_B(); - uint16_t a = 0; - uint16_t b = 0; - uint8_t c = 0; - - switch (insn) { -#define FETCH_Z() /* empty */ -#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; -#include "mruby/ops.h" -#undef OPCODE - } - switch (insn) { - case OP_EXT1: - insn = READ_B(); - switch (insn) { -#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; -#include "mruby/ops.h" -#undef OPCODE - } - break; - case OP_EXT2: - insn = READ_B(); - switch (insn) { -#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; -#include "mruby/ops.h" -#undef OPCODE - } - break; - case OP_EXT3: - insn = READ_B(); - switch (insn) { -#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; -#include "mruby/ops.h" -#undef OPCODE - } - break; - default: - break; - } - data.insn = insn; - data.a = a; - data.b = b; - data.c = c; - return data; -} - -struct mrb_insn_data -mrb_last_insn(codegen_scope *s) -{ - if (s->pc == s->lastpc) { - struct mrb_insn_data data; - - data.insn = OP_NOP; - return data; - } - return mrb_decode_insn(s, &s->iseq[s->lastpc]); -} - -static mrb_bool -no_peephole(codegen_scope *s) -{ - return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc; -} - -static uint16_t -genjmp(codegen_scope *s, mrb_code i, uint16_t pc) -{ - uint16_t pos; - - s->lastpc = s->pc; - gen_B(s, i); - pos = s->pc; - gen_S(s, pc); - return pos; -} - -static uint16_t -genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) -{ - uint16_t pos; - - if (!no_peephole(s) && !val) { - struct mrb_insn_data data = mrb_last_insn(s); - - if (data.insn == OP_MOVE && data.a == a) { - s->pc = s->lastpc; - a = data.b; } } - return genop(s, i); } static void diff --git a/src/vm.c b/src/vm.c index b47469ebf..d0ea6b3bd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1069,16 +1069,6 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_LOADI, BB) { - SET_INT_VALUE(regs[a], b); - NEXT; - } - - CASE(OP_LOADINEG, BB) { - SET_INT_VALUE(regs[a], -b); - NEXT; - } - CASE(OP_LOADI__1,B) goto L_LOADI; CASE(OP_LOADI_0,B) goto L_LOADI; CASE(OP_LOADI_1,B) goto L_LOADI; -- cgit v1.2.3 From 471288f37d18e640f98029fabcdcb7ee16b95d93 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 25 Aug 2018 16:58:01 +0900 Subject: Reduce integer casting warnings. --- include/mruby.h | 2 +- mrbgems/mruby-compiler/core/codegen.c | 8 ++++---- mrbgems/mruby-eval/src/eval.c | 6 +++--- src/codedump.c | 6 +++--- src/load.c | 4 ++-- src/vm.c | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 542d7491f..872396899 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1234,7 +1234,7 @@ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib); * @mrbgem mruby-fiber */ #define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError")) -MRB_API void mrb_stack_extend(mrb_state*, int); +MRB_API void mrb_stack_extend(mrb_state*, mrb_int); /* memory pool implementation */ typedef struct mrb_pool mrb_pool; diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 075945b3b..a835a563e 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -400,7 +400,7 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) } else { gen_B(s, i); - gen_B(s, a); + gen_B(s, (uint8_t)a); pos = s->pc; gen_S(s, pc); } @@ -494,10 +494,10 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) if (data.b >= 128) goto normal; s->pc = s->lastpc; if (op == OP_ADD) { - genop_3(s, OP_ADDI, dst, idx, data.b); + genop_3(s, OP_ADDI, dst, idx, (uint8_t)data.b); } else { - genop_3(s, OP_SUBI, dst, idx, data.b); + genop_3(s, OP_SUBI, dst, idx, (uint8_t)data.b); } break; default: @@ -2441,7 +2441,7 @@ codegen(codegen_scope *s, node *tree, int val) #endif if (i == -1) genop_1(s, OP_LOADI__1, cursp()); else if (i >= -0xffff) { - genop_2(s, OP_LOADINEG, cursp(), -i); + genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i); } else { int off = new_lit(s, mrb_fixnum_value(i)); diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index f1e50e83d..b9c87f6d1 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -154,7 +154,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) if (arg != 0) { /* must replace */ irep->iseq[i] = insn = OP_SETUPVAR; - irep->iseq[i+1] = b; + irep->iseq[i+1] = (mrb_code)b; irep->iseq[i+2] = arg >> 8; irep->iseq[i+3] = arg & 0xff; } @@ -169,7 +169,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) int lev = c+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { - mrb_code arg = search_variable(mrb, tmp->lv[b-1].name, bnest); + uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = OP_GETUPVAR; @@ -188,7 +188,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) int lev = c+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) { - mrb_code arg = search_variable(mrb, tmp->lv[b-1].name, bnest); + uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = OP_SETUPVAR; diff --git a/src/codedump.c b/src/codedump.c index 9174ebe3d..80802778f 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -48,7 +48,7 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) #endif static void -print_header(mrb_irep *irep, int i) +print_header(mrb_irep *irep, ptrdiff_t i) { int32_t line; @@ -60,7 +60,7 @@ print_header(mrb_irep *irep, int i) printf("%5d ", line); } - printf("%03d ", i); + printf("%03d ", (int)i); } #define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn @@ -91,7 +91,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) pc = irep->iseq; pcend = pc + irep->ilen; while (pc < pcend) { - int i; + ptrdiff_t i; uint32_t a; uint16_t b; uint8_t c; diff --git a/src/load.c b/src/load.c index 20878aa56..54b50b14d 100644 --- a/src/load.c +++ b/src/load.c @@ -68,7 +68,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag /* Binary Data Section */ /* ISEQ BLOCK */ - irep->ilen = (size_t)bin_to_uint32(src); + irep->ilen = (uint16_t)bin_to_uint32(src); src += sizeof(uint32_t); src += skip_padding(src); @@ -157,7 +157,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag } /* SYMS BLOCK */ - irep->slen = (size_t)bin_to_uint32(src); /* syms length */ + irep->slen = (uint16_t)bin_to_uint32(src); /* syms length */ src += sizeof(uint32_t); if (irep->slen > 0) { if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) { diff --git a/src/vm.c b/src/vm.c index d0ea6b3bd..44472e311 100644 --- a/src/vm.c +++ b/src/vm.c @@ -218,7 +218,7 @@ stack_extend_alloc(mrb_state *mrb, int room) } MRB_API void -mrb_stack_extend(mrb_state *mrb, int room) +mrb_stack_extend(mrb_state *mrb, mrb_int room) { if (mrb->c->stack + room >= mrb->c->stend) { stack_extend_alloc(mrb, room); -- cgit v1.2.3 From 6aa091e5aadafa11d9f10d9fa7d821cf5e5e379d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 12:37:07 +0900 Subject: Simplified `#ifdef` nesting in `codedump.c`; fix #4089 `printf()` and related functions should not be called when `MRB_DISABLE_STDIO` is defined. --- src/codedump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/codedump.c b/src/codedump.c index 80802778f..454b16b36 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -45,7 +45,6 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) if (b > 0) print_r(mrb, irep, b); printf("\n"); } -#endif static void print_header(mrb_irep *irep, ptrdiff_t i) @@ -68,7 +67,6 @@ print_header(mrb_irep *irep, ptrdiff_t i) static void codedump(mrb_state *mrb, mrb_irep *irep) { -#ifndef MRB_DISABLE_STDIO int ai; mrb_code *pc, *pcend; mrb_code ins; @@ -526,7 +524,6 @@ codedump(mrb_state *mrb, mrb_irep *irep) mrb_gc_arena_restore(mrb, ai); } printf("\n"); -#endif } static void @@ -539,9 +536,12 @@ codedump_recur(mrb_state *mrb, mrb_irep *irep) codedump_recur(mrb, irep->reps[i]); } } +#endif void mrb_codedump_all(mrb_state *mrb, struct RProc *proc) { +#ifndef MRB_DISABLE_STDIO codedump_recur(mrb, proc->body.irep); +#endif } -- cgit v1.2.3 From 98c759e86a73c2e2220c7b9d36a9d78177891273 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 13:17:18 +0900 Subject: Check the size of rescue&ensure stacks; ref #4088 Those small stack indexes can cause integer overflow. --- src/vm.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 44472e311..45d2b5881 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1239,11 +1239,24 @@ RETRY_TRY_BLOCK: } CASE(OP_ONERR, S) { + /* check rescue stack */ + if (mrb->c->ci->ridx == UINT16_MAX) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested rescues"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + /* expand rescue stack */ if (mrb->c->rsize <= mrb->c->ci->ridx) { if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE; - else mrb->c->rsize *= 2; - mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t) * mrb->c->rsize); + else { + mrb->c->rsize *= 2; + if (mrb->c->rsize <= mrb->c->ci->ridx) { + mrb->c->rsize = UINT16_MAX; + } + } + mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t)*mrb->c->rsize); } + /* push rescue stack */ mrb->c->rescue[mrb->c->ci->ridx++] = a; NEXT; } @@ -1292,12 +1305,24 @@ RETRY_TRY_BLOCK: struct RProc *p; p = mrb_closure_new(mrb, irep->reps[a]); - /* push ensure_stack */ + /* check ensure stack */ + if (mrb->c->eidx == UINT16_MAX) { + mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested ensures"); + mrb_exc_set(mrb, exc); + goto L_RAISE; + } + /* expand ensure stack */ if (mrb->c->esize <= mrb->c->eidx+1) { if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE; - else mrb->c->esize *= 2; - mrb->c->ensure = (struct RProc **)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*) * mrb->c->esize); + else { + mrb->c->esize *= 2; + if (mrb->c->esize <= mrb->c->eidx) { + mrb->c->esize = UINT16_MAX; + } + } + mrb->c->ensure = (struct RProc**)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*)*mrb->c->esize); } + /* push ensure stack */ mrb->c->ensure[mrb->c->eidx++] = p; mrb->c->ensure[mrb->c->eidx] = NULL; mrb_gc_arena_restore(mrb, ai); -- cgit v1.2.3 From f76cc483d55b58f2b5803b13cb5e528a67b39c3b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 29 Aug 2018 23:59:20 +0900 Subject: Fix off-by-one error in `OP_EPUSH` and `OP_ONERR`; fix #4095 --- src/vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 45d2b5881..2fd1e5efa 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1240,7 +1240,7 @@ RETRY_TRY_BLOCK: CASE(OP_ONERR, S) { /* check rescue stack */ - if (mrb->c->ci->ridx == UINT16_MAX) { + if (mrb->c->ci->ridx == UINT16_MAX-1) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested rescues"); mrb_exc_set(mrb, exc); goto L_RAISE; @@ -1306,7 +1306,7 @@ RETRY_TRY_BLOCK: p = mrb_closure_new(mrb, irep->reps[a]); /* check ensure stack */ - if (mrb->c->eidx == UINT16_MAX) { + if (mrb->c->eidx == UINT16_MAX-1) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "too many nested ensures"); mrb_exc_set(mrb, exc); goto L_RAISE; -- cgit v1.2.3 From 2c93e4a0a816d9c0d547a27b9f09fa61a2497d95 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 00:15:16 +0900 Subject: The operand of `OP_ARYDUP` may not be an array; fix #4094 This commit also fix #4096. --- src/vm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 2fd1e5efa..c8088d22e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2618,7 +2618,12 @@ RETRY_TRY_BLOCK: CASE(OP_ARYDUP, B) { mrb_value ary = regs[a]; - ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + if (mrb_array_p(ary)) { + ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); + } + else { + ary = mrb_ary_new_from_values(mrb, 1, &ary); + } regs[a] = ary; NEXT; } -- cgit v1.2.3 From 5addd5db4a59450427abae2e9925c529fd6868a1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 01:20:59 +0900 Subject: Need to clear `mrb->c->cibase->ridx` (toplevel ridx) at L_STOP; fix #4092 This problem only appears when `mrb` executed multiple times (i.e. `mirb`) --- src/vm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index c8088d22e..98e554607 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2954,6 +2954,7 @@ RETRY_TRY_BLOCK: while (mrb->c->eidx > 0) { ecall(mrb); } + mrb->c->cibase->ridx = 0; ERR_PC_CLR(mrb); mrb->jmp = prev_jmp; if (mrb->exc) { -- cgit v1.2.3 From e471d37ca5f1422860a1eaa81d4c9f1b3c8b6aed Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 16:07:59 +0900 Subject: Separate meta-programming features to `mruby-metaprog` gem. We assume meta-programming is less used in embedded environments. We have moved following methods: * Kernel module global_variables, local_variables, singleton_class, instance_variables, instance_variables_defined?, instance_variable_get, instance_variable_set, methods, private_methods, public_methods, protected_methods, singleton_methods, define_singleton_methods * Module class class_variables, class_variables_defined?, class_variable_get, class_variable_set, remove_class_variable, included_modules, instance_methods, remove_method, method_removed, constants * Module class methods constants, nesting Note: Following meta-programming methods are kept in the core: * Module class alias_method, undef_method, ancestors, const_defined?, const_get, const_set, remove_const, method_defined?, define_method * Toplevel object define_method `mruby-metaprog` gem is linked by default (specified in default.gembox). When it is removed, it will save 40KB (stripped:8KB) on x86-64 environment last time I measured. --- mrbgems/default.gembox | 3 + mrbgems/mruby-bin-strip/bintest/mruby-strip.rb | 6 +- mrbgems/mruby-class-ext/test/module.rb | 2 +- mrbgems/mruby-eval/test/eval.rb | 2 +- mrbgems/mruby-io/test/io.rb | 2 +- mrbgems/mruby-metaprog/mrbgem.rake | 5 + mrbgems/mruby-metaprog/src/metaprog.c | 701 +++++++++++++++++++++++++ mrbgems/mruby-metaprog/test/metaprog.rb | 303 +++++++++++ mrbgems/mruby-method/mrblib/kernel.rb | 5 +- mrbgems/mruby-method/test/method.rb | 12 +- mrbgems/mruby-toplevel-ext/test/toplevel.rb | 4 +- src/class.c | 446 +++------------- src/etc.c | 1 + src/kernel.c | 401 +------------- test/t/class.rb | 25 +- test/t/codegen.rb | 2 +- test/t/kernel.rb | 91 +--- test/t/module.rb | 258 ++------- 18 files changed, 1149 insertions(+), 1120 deletions(-) create mode 100644 mrbgems/mruby-metaprog/mrbgem.rake create mode 100644 mrbgems/mruby-metaprog/src/metaprog.c create mode 100644 mrbgems/mruby-metaprog/test/metaprog.rb (limited to 'src') diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 7ddbb16d1..23e65fcee 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -1,4 +1,7 @@ MRuby::GemBox.new do |conf| + # Meta-programming features + conf.gem :core => "mruby-metaprog" + # Use standard IO/File class conf.gem :core => "mruby-io" diff --git a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb index bb664a2b1..2db3c10b1 100644 --- a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb +++ b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb @@ -67,7 +67,7 @@ EOS `#{cmd('mruby-strip')} -l #{without_lv.path}` assert_true without_lv.size < with_lv.size - - assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp - assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp +# +# assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp +# assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp end diff --git a/mrbgems/mruby-class-ext/test/module.rb b/mrbgems/mruby-class-ext/test/module.rb index ed6713aac..71a8da451 100644 --- a/mrbgems/mruby-class-ext/test/module.rb +++ b/mrbgems/mruby-class-ext/test/module.rb @@ -26,7 +26,7 @@ end assert 'Module#singleton_class?' do mod = Module.new cls = Class.new - scl = cls.singleton_class + scl = (class < true or false + * + * Returns true if the given instance variable is + * defined in obj. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_defined?(:@a) #=> true + * fred.instance_variable_defined?("@b") #=> true + * fred.instance_variable_defined?("@c") #=> false + */ +static mrb_value +mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) +{ + mrb_sym sym; + + mrb_get_args(mrb, "n", &sym); + mrb_iv_name_sym_check(mrb, sym); + return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); +} + +/* 15.3.1.3.21 */ +/* + * call-seq: + * obj.instance_variable_get(symbol) -> obj + * + * Returns the value of the given instance variable, or nil if the + * instance variable is not set. The @ part of the + * variable name should be included for regular instance + * variables. Throws a NameError exception if the + * supplied symbol is not valid as an instance variable name. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_get(:@a) #=> "cat" + * fred.instance_variable_get("@b") #=> 99 + */ +static mrb_value +mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) +{ + mrb_sym iv_name; + + mrb_get_args(mrb, "n", &iv_name); + mrb_iv_name_sym_check(mrb, iv_name); + return mrb_iv_get(mrb, self, iv_name); +} + +/* 15.3.1.3.22 */ +/* + * call-seq: + * obj.instance_variable_set(symbol, obj) -> obj + * + * Sets the instance variable names by symbol to + * object, thereby frustrating the efforts of the class's + * author to attempt to provide proper encapsulation. The variable + * did not have to exist prior to this call. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_set(:@a, 'dog') #=> "dog" + * fred.instance_variable_set(:@c, 'cat') #=> "cat" + * fred.inspect #=> "#" + */ +static mrb_value +mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) +{ + mrb_sym iv_name; + mrb_value val; + + mrb_get_args(mrb, "no", &iv_name, &val); + mrb_iv_name_sym_check(mrb, iv_name); + mrb_iv_set(mrb, self, iv_name, val); + return val; +} + +/* 15.3.1.2.7 */ +/* + * call-seq: + * local_variables -> array + * + * Returns the names of local variables in the current scope. + * + * [mruby limitation] + * If variable symbol information was stripped out from + * compiled binary files using `mruby-strip -l`, this + * method always returns an empty array. + */ +static mrb_value +mrb_local_variables(mrb_state *mrb, mrb_value self) +{ + struct RProc *proc; + mrb_irep *irep; + mrb_value vars; + size_t i; + + proc = mrb->c->ci[-1].proc; + + if (MRB_PROC_CFUNC_P(proc)) { + return mrb_ary_new(mrb); + } + vars = mrb_hash_new(mrb); + while (proc) { + if (MRB_PROC_CFUNC_P(proc)) break; + irep = proc->body.irep; + if (!irep->lv) break; + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name) { + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); + break; + } + } + } + if (!MRB_PROC_ENV_P(proc)) break; + proc = proc->upper; + //if (MRB_PROC_SCOPE_P(proc)) break; + if (!proc->c) break; + } + + return mrb_hash_keys(mrb, vars); +} + +KHASH_DECLARE(st, mrb_sym, char, FALSE) + +static void +method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) +{ + khint_t i; + + khash_t(mt) *h = klass->mt; + if (!h || kh_size(h) == 0) return; + for (i=0;iflags & MRB_FL_CLASS_IS_PREPENDED)) { + MRB_CLASS_ORIGIN(klass); + prepended = TRUE; + } + + oldklass = 0; + while (klass && (klass != oldklass)) { + method_entry_loop(mrb, klass, set); + if ((klass->tt == MRB_TT_ICLASS && !prepended) || + (klass->tt == MRB_TT_SCLASS)) { + } + else { + if (!recur) break; + } + oldklass = klass; + klass = klass->super; + } + + ary = mrb_ary_new_capa(mrb, kh_size(set)); + for (i=0;i array + * + * Returns a list of the names of methods publicly accessible in + * obj. This will include all the methods accessible in + * obj's ancestors. + * + * class Klass + * def kMethod() + * end + * end + * k = Klass.new + * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?, + * # :class, :instance_variable_set, + * # :methods, :extend, :__send__, :instance_eval] + * k.methods.length #=> 42 + */ +static mrb_value +mrb_obj_methods_m(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */ +} + +/* 15.3.1.3.36 */ +/* + * call-seq: + * obj.private_methods(all=true) -> array + * + * Returns the list of private methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_private_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */ +} + +/* 15.3.1.3.37 */ +/* + * call-seq: + * obj.protected_methods(all=true) -> array + * + * Returns the list of protected methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_protected_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */ +} + +/* 15.3.1.3.38 */ +/* + * call-seq: + * obj.public_methods(all=true) -> array + * + * Returns the list of public methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_public_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */ +} + +static mrb_value +mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj) +{ + khint_t i; + mrb_value ary; + struct RClass* klass; + khash_t(st)* set = kh_init(st, mrb); + + klass = mrb_class(mrb, obj); + + if (klass && (klass->tt == MRB_TT_SCLASS)) { + method_entry_loop(mrb, klass, set); + klass = klass->super; + } + if (recur) { + while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) { + method_entry_loop(mrb, klass, set); + klass = klass->super; + } + } + + ary = mrb_ary_new(mrb); + for (i=0;i array + * + * Returns an array of the names of singleton methods for obj. + * If the optional all parameter is true, the list will include + * methods in modules included in obj. + * Only public and protected singleton methods are returned. + * + * module Other + * def three() end + * end + * + * class Single + * def Single.four() end + * end + * + * a = Single.new + * + * def a.one() + * end + * + * class << a + * include Other + * def two() + * end + * end + * + * Single.singleton_methods #=> [:four] + * a.singleton_methods(false) #=> [:two, :one] + * a.singleton_methods #=> [:two, :one, :three] + */ +static mrb_value +mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_singleton_methods(mrb, recur, self); +} + +static mrb_value +mod_define_singleton_method(mrb_state *mrb, mrb_value self) +{ + struct RProc *p; + mrb_method_t m; + mrb_sym mid; + mrb_value blk = mrb_nil_value(); + + mrb_get_args(mrb, "n&", &mid, &blk); + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + p->flags |= MRB_PROC_STRICT; + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m); + return mrb_symbol_value(mid); +} + +static void +check_cv_name_str(mrb_state *mrb, mrb_value str) +{ + const char *s = RSTRING_PTR(str); + mrb_int len = RSTRING_LEN(str); + + if (len < 3 || !(s[0] == '@' && s[1] == '@')) { + mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); + } +} + +static void +check_cv_name_sym(mrb_state *mrb, mrb_sym id) +{ + check_cv_name_str(mrb, mrb_sym2str(mrb, id)); +} + +/* 15.2.2.4.39 */ +/* + * call-seq: + * remove_class_variable(sym) -> obj + * + * Removes the definition of the sym, returning that + * constant's value. + * + * class Dummy + * @@var = 99 + * puts @@var + * p class_variables + * remove_class_variable(:@@var) + * p class_variables + * end + * + * produces: + * + * 99 + * [:@@var] + * [] + */ + +static mrb_value +mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) +{ + mrb_value val; + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + + val = mrb_iv_remove(mrb, mod, id); + if (!mrb_undef_p(val)) return val; + + if (mrb_cv_defined(mrb, mod, id)) { + mrb_name_error(mrb, id, "cannot remove %S for %S", + mrb_sym2str(mrb, id), mod); + } + + mrb_name_error(mrb, id, "class variable %S not defined for %S", + mrb_sym2str(mrb, id), mod); + + /* not reached */ + return mrb_nil_value(); +} + +/* 15.2.2.4.16 */ +/* + * call-seq: + * obj.class_variable_defined?(symbol) -> true or false + * + * Returns true if the given class variable is defined + * in obj. + * + * class Fred + * @@foo = 99 + * end + * Fred.class_variable_defined?(:@@foo) #=> true + * Fred.class_variable_defined?(:@@bar) #=> false + */ + +static mrb_value +mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + return mrb_bool_value(mrb_cv_defined(mrb, mod, id)); +} + +/* 15.2.2.4.17 */ +/* + * call-seq: + * mod.class_variable_get(symbol) -> obj + * + * Returns the value of the given class variable (or throws a + * NameError exception). The @@ part of the + * variable name should be included for regular class variables + * + * class Fred + * @@foo = 99 + * end + * Fred.class_variable_get(:@@foo) #=> 99 + */ + +static mrb_value +mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + return mrb_cv_get(mrb, mod, id); +} + +/* 15.2.2.4.18 */ +/* + * call-seq: + * obj.class_variable_set(symbol, obj) -> obj + * + * Sets the class variable names by symbol to + * object. + * + * class Fred + * @@foo = 99 + * def foo + * @@foo + * end + * end + * Fred.class_variable_set(:@@foo, 101) #=> 101 + * Fred.new.foo #=> 101 + */ + +static mrb_value +mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod) +{ + mrb_value value; + mrb_sym id; + + mrb_get_args(mrb, "no", &id, &value); + check_cv_name_sym(mrb, id); + mrb_cv_set(mrb, mod, id, value); + return value; +} + +static mrb_value +mrb_mod_included_modules(mrb_state *mrb, mrb_value self) +{ + mrb_value result; + struct RClass *c = mrb_class_ptr(self); + struct RClass *origin = c; + + MRB_CLASS_ORIGIN(origin); + result = mrb_ary_new(mrb); + while (c) { + if (c != origin && c->tt == MRB_TT_ICLASS) { + if (c->c->tt == MRB_TT_MODULE) { + mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + } + } + c = c->super; + } + + return result; +} + +mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); + +/* 15.2.2.4.33 */ +/* + * call-seq: + * mod.instance_methods(include_super=true) -> array + * + * Returns an array containing the names of the public and protected instance + * methods in the receiver. For a module, these are the public and protected methods; + * for a class, they are the instance (not singleton) methods. With no + * argument, or with an argument that is false, the + * instance methods in mod are returned, otherwise the methods + * in mod and mod's superclasses are returned. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * def method3() end + * end + * + * A.instance_methods #=> [:method1] + * B.instance_methods(false) #=> [:method2] + * C.instance_methods(false) #=> [:method3] + * C.instance_methods(true).length #=> 43 + */ + +static mrb_value +mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_class_instance_method_list(mrb, recur, c, 0); +} + +static void +remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) +{ + struct RClass *c = mrb_class_ptr(mod); + khash_t(mt) *h; + khiter_t k; + + MRB_CLASS_ORIGIN(c); + h = c->mt; + + if (h) { + k = kh_get(mt, mrb, h, mid); + if (k != kh_end(h)) { + kh_del(mt, mrb, h, k); + mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); + return; + } + } + + mrb_name_error(mrb, mid, "method '%S' not defined in %S", + mrb_sym2str(mrb, mid), mod); +} + +/* 15.2.2.4.41 */ +/* + * call-seq: + * remove_method(symbol) -> self + * + * Removes the method identified by _symbol_ from the current + * class. For an example, see Module.undef_method. + */ + +static mrb_value +mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) +{ + mrb_int argc; + mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + while (argc--) { + remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv)); + argv++; + } + return mod; +} + +static mrb_value +mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented"); + return mrb_nil_value(); /* not reached */ +} + +/* implementation of Module.nesting */ +mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); + +void +mrb_mruby_metaprog_gem_init(mrb_state* mrb) +{ + struct RClass *krn = mrb->kernel_module; + struct RClass *mod = mrb->module_class; + + mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ + mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ + + mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ + mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ + mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */ + mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */ + mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ + mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */ + mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */ + mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ + mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ + mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); + + mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ + mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ + mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */ + mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */ + mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ + mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ + mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ + mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "method_removed", mrb_f_nil, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ + mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ + mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */ +} + +void +mrb_mruby_metaprog_gem_final(mrb_state* mrb) +{ +} diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb new file mode 100644 index 000000000..587d00d6f --- /dev/null +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -0,0 +1,303 @@ + +assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do + o = Object.new + o.instance_variable_set(:@a, 1) + + assert_true o.instance_variable_defined?("@a") + assert_false o.instance_variable_defined?("@b") + assert_true o.instance_variable_defined?("@a"[0,2]) + assert_true o.instance_variable_defined?("@abc"[0,2]) +end + +assert('Kernel#instance_variables', '15.3.1.3.23') do + o = Object.new + o.instance_eval do + @a = 11 + @b = 12 + end + ivars = o.instance_variables + + assert_equal Array, ivars.class, + assert_equal(2, ivars.size) + assert_true ivars.include?(:@a) + assert_true ivars.include?(:@b) +end + +assert('Kernel#methods', '15.3.1.3.31') do + assert_equal Array, methods.class +end + +assert('Kernel#private_methods', '15.3.1.3.36') do + assert_equal Array, private_methods.class +end + +assert('Kernel#protected_methods', '15.3.1.3.37') do + assert_equal Array, protected_methods.class +end + +assert('Kernel#public_methods', '15.3.1.3.38') do + assert_equal Array, public_methods.class + class Foo + def foo + end + end + assert_equal [:foo], Foo.new.public_methods(false) +end + +assert('Kernel#singleton_methods', '15.3.1.3.45') do + assert_equal singleton_methods.class, Array +end + +assert('Kernel.local_variables', '15.3.1.2.7') do + a, b = 0, 1 + a += b + + vars = Kernel.local_variables.sort + assert_equal [:a, :b, :vars], vars + + assert_equal [:a, :b, :c, :vars], Proc.new { |a, b| + c = 2 + # Kernel#local_variables: 15.3.1.3.28 + local_variables.sort + }.call(-1, -2) +end + +assert('Kernel#define_singleton_method') do + o = Object.new + ret = o.define_singleton_method(:test_method) do + :singleton_method_ok + end + assert_equal :test_method, ret + assert_equal :singleton_method_ok, o.test_method +end + +def labeled_module(name, &block) + Module.new do + (class <tt == MRB_TT_ICLASS) { - if (c->c->tt == MRB_TT_MODULE) { - mrb_ary_push(mrb, result, mrb_obj_value(c->c)); - } - } - c = c->super; - } - - return result; -} - static mrb_value mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { @@ -1250,45 +1214,6 @@ mrb_mod_initialize(mrb_state *mrb, mrb_value mod) return mod; } -mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); - -/* 15.2.2.4.33 */ -/* - * call-seq: - * mod.instance_methods(include_super=true) -> array - * - * Returns an array containing the names of the public and protected instance - * methods in the receiver. For a module, these are the public and protected methods; - * for a class, they are the instance (not singleton) methods. With no - * argument, or with an argument that is false, the - * instance methods in mod are returned, otherwise the methods - * in mod and mod's superclasses are returned. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * def method3() end - * end - * - * A.instance_methods #=> [:method1] - * B.instance_methods(false) #=> [:method2] - * C.instance_methods(false) #=> [:method3] - * C.instance_methods(true).length #=> 43 - */ - -static mrb_value -mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) -{ - struct RClass *c = mrb_class_ptr(mod); - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_class_instance_method_list(mrb, recur, c, 0); -} - /* implementation of module_eval/class_eval */ mrb_value mrb_mod_module_eval(mrb_state*, mrb_value); @@ -1994,270 +1919,6 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static mrb_value -mod_define_method(mrb_state *mrb, mrb_value self) -{ - struct RClass *c = mrb_class_ptr(self); - struct RProc *p; - mrb_method_t m; - mrb_sym mid; - mrb_value proc = mrb_undef_value(); - mrb_value blk; - - mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); - switch (mrb_type(proc)) { - case MRB_TT_PROC: - blk = proc; - break; - case MRB_TT_UNDEF: - /* ignored */ - break; - default: - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); - break; - } - if (mrb_nil_p(blk)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); - } - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); - mrb_proc_copy(p, mrb_proc_ptr(blk)); - p->flags |= MRB_PROC_STRICT; - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, mid, m); - return mrb_symbol_value(mid); -} - -static mrb_value -top_define_method(mrb_state *mrb, mrb_value self) -{ - return mod_define_method(mrb, mrb_obj_value(mrb->object_class)); -} - -static void -check_cv_name_str(mrb_state *mrb, mrb_value str) -{ - const char *s = RSTRING_PTR(str); - mrb_int len = RSTRING_LEN(str); - - if (len < 3 || !(s[0] == '@' && s[1] == '@')) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); - } -} - -static void -check_cv_name_sym(mrb_state *mrb, mrb_sym id) -{ - check_cv_name_str(mrb, mrb_sym2str(mrb, id)); -} - -/* 15.2.2.4.16 */ -/* - * call-seq: - * obj.class_variable_defined?(symbol) -> true or false - * - * Returns true if the given class variable is defined - * in obj. - * - * class Fred - * @@foo = 99 - * end - * Fred.class_variable_defined?(:@@foo) #=> true - * Fred.class_variable_defined?(:@@bar) #=> false - */ - -static mrb_value -mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - return mrb_bool_value(mrb_cv_defined(mrb, mod, id)); -} - -/* 15.2.2.4.17 */ -/* - * call-seq: - * mod.class_variable_get(symbol) -> obj - * - * Returns the value of the given class variable (or throws a - * NameError exception). The @@ part of the - * variable name should be included for regular class variables - * - * class Fred - * @@foo = 99 - * end - * Fred.class_variable_get(:@@foo) #=> 99 - */ - -static mrb_value -mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - return mrb_cv_get(mrb, mod, id); -} - -/* 15.2.2.4.18 */ -/* - * call-seq: - * obj.class_variable_set(symbol, obj) -> obj - * - * Sets the class variable names by symbol to - * object. - * - * class Fred - * @@foo = 99 - * def foo - * @@foo - * end - * end - * Fred.class_variable_set(:@@foo, 101) #=> 101 - * Fred.new.foo #=> 101 - */ - -static mrb_value -mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod) -{ - mrb_value value; - mrb_sym id; - - mrb_get_args(mrb, "no", &id, &value); - check_cv_name_sym(mrb, id); - mrb_cv_set(mrb, mod, id, value); - return value; -} - -/* 15.2.2.4.39 */ -/* - * call-seq: - * remove_class_variable(sym) -> obj - * - * Removes the definition of the sym, returning that - * constant's value. - * - * class Dummy - * @@var = 99 - * puts @@var - * p class_variables - * remove_class_variable(:@@var) - * p class_variables - * end - * - * produces: - * - * 99 - * [:@@var] - * [] - */ - -static mrb_value -mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) -{ - mrb_value val; - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - - val = mrb_iv_remove(mrb, mod, id); - if (!mrb_undef_p(val)) return val; - - if (mrb_cv_defined(mrb, mod, id)) { - mrb_name_error(mrb, id, "cannot remove %S for %S", - mrb_sym2str(mrb, id), mod); - } - - mrb_name_error(mrb, id, "class variable %S not defined for %S", - mrb_sym2str(mrb, id), mod); - - /* not reached */ - return mrb_nil_value(); -} - -/* 15.2.2.4.34 */ -/* - * call-seq: - * mod.method_defined?(symbol) -> true or false - * - * Returns +true+ if the named method is defined by - * _mod_ (or its included modules and, if _mod_ is a class, - * its ancestors). Public and protected methods are matched. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * include A - * def method3() end - * end - * - * A.method_defined? :method1 #=> true - * C.method_defined? "method1" #=> true - * C.method_defined? "method2" #=> true - * C.method_defined? "method3" #=> true - * C.method_defined? "method4" #=> false - */ - -static mrb_value -mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); -} - -static void -remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) -{ - struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = find_origin(c)->mt; - khiter_t k; - - if (h) { - k = kh_get(mt, mrb, h, mid); - if (k != kh_end(h)) { - kh_del(mt, mrb, h, k); - mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); - return; - } - } - - mrb_name_error(mrb, mid, "method '%S' not defined in %S", - mrb_sym2str(mrb, mid), mod); -} - -/* 15.2.2.4.41 */ -/* - * call-seq: - * remove_method(symbol) -> self - * - * Removes the method identified by _symbol_ from the current - * class. For an example, see Module.undef_method. - */ - -static mrb_value -mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) -{ - mrb_int argc; - mrb_value *argv; - - mrb_get_args(mrb, "*", &argv, &argc); - while (argc--) { - remove_method(mrb, mod, to_sym(mrb, *argv)); - argv++; - } - return mod; -} - - - static void check_const_name_str(mrb_state *mrb, mrb_value str) { @@ -2272,15 +1933,6 @@ check_const_name_sym(mrb_state *mrb, mrb_sym id) check_const_name_str(mrb, mrb_sym2str(mrb, id)); } -static mrb_value -const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit) -{ - if (inherit) { - return mrb_bool_value(mrb_const_defined(mrb, mod, id)); - } - return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); -} - static mrb_value mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) { @@ -2289,7 +1941,10 @@ mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "n|b", &id, &inherit); check_const_name_sym(mrb, id); - return const_defined(mrb, mod, id, inherit); + if (inherit) { + return mrb_bool_value(mrb_const_defined(mrb, mod, id)); + } + return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); } static mrb_value @@ -2379,11 +2034,79 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } +/* 15.2.2.4.34 */ +/* + * call-seq: + * mod.method_defined?(symbol) -> true or false + * + * Returns +true+ if the named method is defined by + * _mod_ (or its included modules and, if _mod_ is a class, + * its ancestors). Public and protected methods are matched. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * include A + * def method3() end + * end + * + * A.method_defined? :method1 #=> true + * C.method_defined? "method1" #=> true + * C.method_defined? "method2" #=> true + * C.method_defined? "method3" #=> true + * C.method_defined? "method4" #=> false + */ + static mrb_value -mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) +mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) { - mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented"); - return mrb_nil_value(); /* not reached */ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); +} + +static mrb_value +mod_define_method(mrb_state *mrb, mrb_value self) +{ + struct RClass *c = mrb_class_ptr(self); + struct RProc *p; + mrb_method_t m; + mrb_sym mid; + mrb_value proc = mrb_undef_value(); + mrb_value blk; + + mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); + switch (mrb_type(proc)) { + case MRB_TT_PROC: + blk = proc; + break; + case MRB_TT_UNDEF: + /* ignored */ + break; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + break; + } + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + p->flags |= MRB_PROC_STRICT; + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, c, mid, m); + return mrb_symbol_value(mid); +} + +static mrb_value +top_define_method(mrb_state *mrb, mrb_value self) +{ + return mod_define_method(mrb, mrb_obj_value(mrb->object_class)); } static mrb_value @@ -2439,8 +2162,6 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod) mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self); /* implementation of instance_eval */ mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); -/* implementation of Module.nesting */ -mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); static mrb_value inspect_main(mrb_state *mrb, mrb_value mod) @@ -2500,9 +2221,6 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); - mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */ - mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */ - mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1)); @@ -2511,18 +2229,12 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */ mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.15 */ mrb_define_method(mrb, mod, "included", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */ - mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ mrb_define_method(mrb, mod, "initialize", mrb_mod_initialize, MRB_ARGS_NONE()); /* 15.2.2.4.31 */ - mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ - mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */ mrb_define_method(mrb, mod, "module_function", mrb_mod_module_function, MRB_ARGS_ANY()); mrb_define_method(mrb, mod, "private", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.36 */ mrb_define_method(mrb, mod, "protected", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.37 */ mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ - mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ - mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ - mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); @@ -2533,14 +2245,12 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */ mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */ mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */ - mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4 +.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ - mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */ mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); diff --git a/src/etc.c b/src/etc.c index 1b8d44a53..12d948a55 100644 --- a/src/etc.c +++ b/src/etc.c @@ -75,6 +75,7 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name) if (mrb_nil_p(name)) { name = mrb_inspect(mrb, name); mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); + /* not reached */ } /* fall through */ case MRB_TT_STRING: diff --git a/src/kernel.c b/src/kernel.c index fed64e9b0..db576b20d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,20 +14,6 @@ #include #include -typedef enum { - NOEX_PUBLIC = 0x00, - NOEX_NOSUPER = 0x01, - NOEX_PRIVATE = 0x02, - NOEX_PROTECTED = 0x04, - NOEX_MASK = 0x06, - NOEX_BASIC = 0x08, - NOEX_UNDEF = NOEX_NOSUPER, - NOEX_MODFUNC = 0x12, - NOEX_SUPER = 0x20, - NOEX_VCALL = 0x40, - NOEX_RESPONDS = 0x80 -} mrb_method_flag_t; - MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) { @@ -551,96 +537,6 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self) return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg))); } -/* 15.3.1.3.20 */ -/* - * call-seq: - * obj.instance_variable_defined?(symbol) -> true or false - * - * Returns true if the given instance variable is - * defined in obj. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_defined?(:@a) #=> true - * fred.instance_variable_defined?("@b") #=> true - * fred.instance_variable_defined?("@c") #=> false - */ -static mrb_value -mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) -{ - mrb_sym sym; - - mrb_get_args(mrb, "n", &sym); - mrb_iv_name_sym_check(mrb, sym); - return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); -} - -/* 15.3.1.3.21 */ -/* - * call-seq: - * obj.instance_variable_get(symbol) -> obj - * - * Returns the value of the given instance variable, or nil if the - * instance variable is not set. The @ part of the - * variable name should be included for regular instance - * variables. Throws a NameError exception if the - * supplied symbol is not valid as an instance variable name. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_get(:@a) #=> "cat" - * fred.instance_variable_get("@b") #=> 99 - */ -static mrb_value -mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) -{ - mrb_sym iv_name; - - mrb_get_args(mrb, "n", &iv_name); - mrb_iv_name_sym_check(mrb, iv_name); - return mrb_iv_get(mrb, self, iv_name); -} - -/* 15.3.1.3.22 */ -/* - * call-seq: - * obj.instance_variable_set(symbol, obj) -> obj - * - * Sets the instance variable names by symbol to - * object, thereby frustrating the efforts of the class's - * author to attempt to provide proper encapsulation. The variable - * did not have to exist prior to this call. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_set(:@a, 'dog') #=> "dog" - * fred.instance_variable_set(:@c, 'cat') #=> "cat" - * fred.inspect #=> "#" - */ -static mrb_value -mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) -{ - mrb_sym iv_name; - mrb_value val; - - mrb_get_args(mrb, "no", &iv_name, &val); - mrb_iv_name_sym_check(mrb, iv_name); - mrb_iv_set(mrb, self, iv_name, val); - return val; -} - /* 15.3.1.3.24 */ /* 15.3.1.3.26 */ /* @@ -681,124 +577,6 @@ mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self) KHASH_DECLARE(st, mrb_sym, char, FALSE) KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal) -static void -method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) -{ - khint_t i; - - khash_t(mt) *h = klass->mt; - if (!h || kh_size(h) == 0) return; - for (i=0;iflags & MRB_FL_CLASS_IS_PREPENDED)) { - MRB_CLASS_ORIGIN(klass); - prepended = TRUE; - } - - oldklass = 0; - while (klass && (klass != oldklass)) { - method_entry_loop(mrb, klass, set); - if ((klass->tt == MRB_TT_ICLASS && !prepended) || - (klass->tt == MRB_TT_SCLASS)) { - } - else { - if (!recur) break; - } - oldklass = klass; - klass = klass->super; - } - - ary = mrb_ary_new_capa(mrb, kh_size(set)); - for (i=0;itt == MRB_TT_SCLASS)) { - method_entry_loop(mrb, klass, set); - klass = klass->super; - } - if (recur) { - while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) { - method_entry_loop(mrb, klass, set); - klass = klass->super; - } - } - - ary = mrb_ary_new(mrb); - for (i=0;i array - * - * Returns a list of the names of methods publicly accessible in - * obj. This will include all the methods accessible in - * obj's ancestors. - * - * class Klass - * def kMethod() - * end - * end - * k = Klass.new - * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?, - * # :class, :instance_variable_set, - * # :methods, :extend, :__send__, :instance_eval] - * k.methods.length #=> 42 - */ -static mrb_value -mrb_obj_methods_m(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */ -} - /* 15.3.1.3.32 */ /* * call_seq: @@ -813,57 +591,6 @@ mrb_false(mrb_state *mrb, mrb_value self) return mrb_false_value(); } -/* 15.3.1.3.36 */ -/* - * call-seq: - * obj.private_methods(all=true) -> array - * - * Returns the list of private methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_private_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */ -} - -/* 15.3.1.3.37 */ -/* - * call-seq: - * obj.protected_methods(all=true) -> array - * - * Returns the list of protected methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_protected_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */ -} - -/* 15.3.1.3.38 */ -/* - * call-seq: - * obj.public_methods(all=true) -> array - * - * Returns the list of public methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_public_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */ -} - /* 15.3.1.2.12 */ /* 15.3.1.3.40 */ /* @@ -1084,67 +811,6 @@ obj_respond_to(mrb_state *mrb, mrb_value self) return mrb_bool_value(respond_to_p); } -/* 15.3.1.3.45 */ -/* - * call-seq: - * obj.singleton_methods(all=true) -> array - * - * Returns an array of the names of singleton methods for obj. - * If the optional all parameter is true, the list will include - * methods in modules included in obj. - * Only public and protected singleton methods are returned. - * - * module Other - * def three() end - * end - * - * class Single - * def Single.four() end - * end - * - * a = Single.new - * - * def a.one() - * end - * - * class << a - * include Other - * def two() - * end - * end - * - * Single.singleton_methods #=> [:four] - * a.singleton_methods(false) #=> [:two, :one] - * a.singleton_methods #=> [:two, :one, :three] - */ -static mrb_value -mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_singleton_methods(mrb, recur, self); -} - -static mrb_value -mod_define_singleton_method(mrb_state *mrb, mrb_value self) -{ - struct RProc *p; - mrb_method_t m; - mrb_sym mid; - mrb_value blk = mrb_nil_value(); - - mrb_get_args(mrb, "n&", &mid, &blk); - if (mrb_nil_p(blk)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); - } - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); - mrb_proc_copy(p, mrb_proc_ptr(blk)); - p->flags |= MRB_PROC_STRICT; - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m); - return mrb_symbol_value(mid); -} - static mrb_value mrb_obj_ceqq(mrb_state *mrb, mrb_value self) { @@ -1162,58 +828,6 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) return mrb_false_value(); } -/* 15.3.1.2.7 */ -/* - * call-seq: - * local_variables -> array - * - * Returns the names of local variables in the current scope. - * - * [mruby limitation] - * If variable symbol information was stripped out from - * compiled binary files using `mruby-strip -l`, this - * method always returns an empty array. - */ -static mrb_value -mrb_local_variables(mrb_state *mrb, mrb_value self) -{ - struct RProc *proc; - mrb_irep *irep; - mrb_value vars; - size_t i; - - proc = mrb->c->ci[-1].proc; - - if (MRB_PROC_CFUNC_P(proc)) { - return mrb_ary_new(mrb); - } - vars = mrb_hash_new(mrb); - while (proc) { - if (MRB_PROC_CFUNC_P(proc)) break; - irep = proc->body.irep; - if (!irep->lv) break; - for (i = 0; i + 1 < irep->nlocals; ++i) { - if (irep->lv[i].name) { - mrb_sym sym = irep->lv[i].name; - const char *name = mrb_sym2name(mrb, sym); - switch (name[0]) { - case '*': case '&': - break; - default: - mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); - break; - } - } - } - if (!MRB_PROC_ENV_P(proc)) break; - proc = proc->upper; - //if (MRB_PROC_SCOPE_P(proc)) break; - if (!proc->c) break; - } - - return mrb_hash_keys(mrb, vars); -} - mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); void mrb_init_kernel(mrb_state *mrb) @@ -1222,13 +836,10 @@ mrb_init_kernel(mrb_state *mrb) mrb->kernel_module = krn = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */ mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */ - mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */ - mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */ ; /* 15.3.1.2.11 */ mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_OPT(2)); /* 15.3.1.2.12 */ - mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ @@ -1245,29 +856,19 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */ - mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ - mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ - mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */ - mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */ + mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */ mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */ mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */ - mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ #ifdef MRB_DEFAULT_METHOD_MISSING mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ #endif - mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */ mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */ - mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */ - mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */ - mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */ mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */ mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ - mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ - mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ diff --git a/test/t/class.rb b/test/t/class.rb index a5118fa93..85450f200 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -36,7 +36,7 @@ end assert('Class#new', '15.2.3.3.3') do assert_raise(TypeError, 'Singleton should raise TypeError') do - "a".singleton_class.new + (class <<"a"; self; end).new end class TestClass @@ -293,15 +293,7 @@ assert('singleton tests') do end end - assert_false baz.singleton_methods.include? :run_foo_mod - assert_false baz.singleton_methods.include? :run_baz - - assert_raise(NoMethodError, 'should raise NoMethodError') do - baz.run_foo_mod - end - assert_raise(NoMethodError, 'should raise NoMethodError') do - baz.run_baz - end + assert_equal :run_baz, baz assert_raise(NoMethodError, 'should raise NoMethodError') do bar.run_foo_mod @@ -318,8 +310,8 @@ assert('singleton tests') do self end - assert_true baz.singleton_methods.include? :run_baz - assert_true baz.singleton_methods.include? :run_foo_mod + assert_true baz.respond_to? :run_baz + assert_true baz.respond_to? :run_foo_mod assert_equal 100, baz.run_foo_mod assert_equal 300, baz.run_baz @@ -440,12 +432,3 @@ assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } end - -assert("remove_method doesn't segfault if the passed in argument isn't a symbol") do - klass = Class.new - assert_raise(TypeError) { klass.remove_method nil } - assert_raise(TypeError) { klass.remove_method 123 } - assert_raise(TypeError) { klass.remove_method 1.23 } - assert_raise(NameError) { klass.remove_method "hello" } - assert_raise(TypeError) { klass.remove_method Class.new } -end diff --git a/test/t/codegen.rb b/test/t/codegen.rb index 4c9e2c594..154d44168 100644 --- a/test/t/codegen.rb +++ b/test/t/codegen.rb @@ -194,4 +194,4 @@ assert('register window of calls (#3783)') do alias send2 send end end -end \ No newline at end of file +end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 561118302..9744bddba 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -103,7 +103,7 @@ assert('Kernel#__send__', '15.3.1.3.4') do # test with argument assert_true __send__(:respond_to?, :nil?) # test without argument and without block - assert_equal Array, __send__(:public_methods).class + assert_equal String, __send__(:to_s).class end assert('Kernel#block_given?', '15.3.1.3.6') do @@ -278,30 +278,6 @@ assert('Kernel#inspect', '15.3.1.3.17') do assert_equal "main", s end -assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do - o = Object.new - o.instance_variable_set(:@a, 1) - - assert_true o.instance_variable_defined?("@a") - assert_false o.instance_variable_defined?("@b") - assert_true o.instance_variable_defined?("@a"[0,2]) - assert_true o.instance_variable_defined?("@abc"[0,2]) -end - -assert('Kernel#instance_variables', '15.3.1.3.23') do - o = Object.new - o.instance_eval do - @a = 11 - @b = 12 - end - ivars = o.instance_variables - - assert_equal Array, ivars.class, - assert_equal(2, ivars.size) - assert_true ivars.include?(:@a) - assert_true ivars.include?(:@b) -end - assert('Kernel#is_a?', '15.3.1.3.24') do assert_true is_a?(Kernel) assert_false is_a?(Array) @@ -381,10 +357,6 @@ assert('Kernel#method_missing', '15.3.1.3.30') do end end -assert('Kernel#methods', '15.3.1.3.31') do - assert_equal Array, methods.class -end - assert('Kernel#nil?', '15.3.1.3.32') do assert_false nil? end @@ -408,23 +380,6 @@ end # Kernel#print is defined in mruby-print mrbgem. '15.3.1.3.35' -assert('Kernel#private_methods', '15.3.1.3.36') do - assert_equal Array, private_methods.class -end - -assert('Kernel#protected_methods', '15.3.1.3.37') do - assert_equal Array, protected_methods.class -end - -assert('Kernel#public_methods', '15.3.1.3.38') do - assert_equal Array, public_methods.class - class Foo - def foo - end - end - assert_equal [:foo], Foo.new.public_methods(false) -end - # Kernel#puts is defined in mruby-print mrbgem. '15.3.1.3.39' assert('Kernel#raise', '15.3.1.3.40') do @@ -496,46 +451,13 @@ assert('Kernel#send', '15.3.1.3.44') do # test with argument assert_true send(:respond_to?, :nil?) # test without argument and without block - assert_equal send(:public_methods).class, Array -end - -assert('Kernel#singleton_methods', '15.3.1.3.45') do - assert_equal singleton_methods.class, Array + assert_equal send(:to_s).class, String end assert('Kernel#to_s', '15.3.1.3.46') do assert_equal to_s.class, String end -assert('Kernel#to_s on primitives') do - begin - Fixnum.alias_method :to_s_, :to_s - Fixnum.remove_method :to_s - - assert_nothing_raised do - # segfaults if mrb_cptr is used - 1.to_s - end - ensure - Fixnum.alias_method :to_s, :to_s_ - Fixnum.remove_method :to_s_ - end -end - -assert('Kernel.local_variables', '15.3.1.2.7') do - a, b = 0, 1 - a += b - - vars = Kernel.local_variables.sort - assert_equal [:a, :b, :vars], vars - - assert_equal [:a, :b, :c, :vars], Proc.new { |a, b| - c = 2 - # Kernel#local_variables: 15.3.1.3.28 - local_variables.sort - }.call(-1, -2) -end - assert('Kernel#!=') do str1 = "hello" str2 = str1 @@ -585,15 +507,6 @@ assert('Kernel#global_variables') do end end -assert('Kernel#define_singleton_method') do - o = Object.new - ret = o.define_singleton_method(:test_method) do - :singleton_method_ok - end - assert_equal :test_method, ret - assert_equal :singleton_method_ok, o.test_method -end - assert('stack extend') do def recurse(count, stop) return count if count > stop diff --git a/test/t/module.rb b/test/t/module.rb index fb82fc934..fda375721 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -3,7 +3,7 @@ def labeled_module(name, &block) Module.new do - singleton_class.class_eval do + (class < Date: Thu, 30 Aug 2018 22:14:10 +0900 Subject: Add new function `mrb_ensure_hash_type()`; ref #4097 Unlike `mrb_check_hash_type()` that returns `nil` if the argument is not a `Hash`, `mrb_ensure_hash_type()` raises a `TypeError` exception. --- include/mruby/hash.h | 1 + src/hash.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 2026c8e0d..449a7d4bc 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -25,6 +25,7 @@ struct RHash { #define mrb_hash_value(p) mrb_obj_value((void*)(p)) MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int); +MRB_API mrb_value mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash); MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); /* diff --git a/src/hash.c b/src/hash.c index 122f5b5d5..7d81bc343 100644 --- a/src/hash.c +++ b/src/hash.c @@ -320,6 +320,12 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) return; } +MRB_API mrb_value +mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) +{ + return mrb_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); +} + MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash) { @@ -959,7 +965,7 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) khiter_t k; mrb_hash_modify(mrb, hash1); - hash2 = mrb_check_hash_type(mrb, hash2); + hash2 = mrb_ensure_hash_type(mrb, hash2); h1 = RHASH_TBL(hash1); h2 = RHASH_TBL(hash2); -- cgit v1.2.3 From 50b840c9de7a0a37d42742a53757f2e74447c053 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 22:18:27 +0900 Subject: Use `mrb_ensure_hash_type()` to check if an operand is a `Hash`; fix #4097 --- src/vm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 98e554607..77d9316d4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2720,10 +2720,11 @@ RETRY_TRY_BLOCK: } CASE(OP_HASHADD, BB) { - mrb_value hash = regs[a]; + mrb_value hash; int i; int lim = a+b*2+1; + hash = mrb_ensure_hash_type(mrb, regs[a]); for (i=a+1; i Date: Sat, 1 Sep 2018 09:35:46 +0900 Subject: Fix ISO/JIS section numbers. --- mrblib/kernel.rb | 2 +- src/class.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/mrblib/kernel.rb b/mrblib/kernel.rb index 550ae8172..4700684b6 100644 --- a/mrblib/kernel.rb +++ b/mrblib/kernel.rb @@ -6,7 +6,7 @@ module Kernel # 15.3.1.2.1 Kernel.` # provided by Kernel#` - # 15.3.1.3.5 + # 15.3.1.3.3 def `(s) raise NotImplementedError.new("backquotes not implemented") end diff --git a/src/class.c b/src/class.c index f8d60d79a..e074cbc3b 100644 --- a/src/class.c +++ b/src/class.c @@ -2210,8 +2210,8 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE()); mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ - mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); -- cgit v1.2.3 From 593c12a5cd670cfdb45741377236207a56541d37 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 11:18:12 +0900 Subject: Avoid `NoMethodError` exception from `mrb_func_basic_p`. --- src/kernel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index db576b20d..248fa5266 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -17,7 +17,8 @@ MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) { - mrb_method_t m = mrb_method_search(mrb, mrb_class(mrb, obj), mid); + struct RClass *c = mrb_class(mrb, obj); + mrb_method_t m = mrb_method_search_vm(mrb, &c, mid); struct RProc *p; if (MRB_METHOD_UNDEF_P(m)) return FALSE; -- cgit v1.2.3 From b80e0ef7428b613a682da4d2a251c8beb24d6dd2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 11:20:30 +0900 Subject: Move `Kernel#send` to `mruby-metaprog` gem. But `BasicObject#__send__` is still available from the core. --- mrbgems/mruby-eval/test/eval.rb | 2 +- mrbgems/mruby-metaprog/src/metaprog.c | 1 + mrbgems/mruby-metaprog/test/metaprog.rb | 27 ++++++++ mrbgems/mruby-method/test/method.rb | 5 +- src/kernel.c | 1 - test/t/codegen.rb | 4 +- test/t/kernel.rb | 28 --------- test/t/module.rb | 106 ++++++++++++++++---------------- 8 files changed, 85 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-eval/test/eval.rb b/mrbgems/mruby-eval/test/eval.rb index a710a1fc0..4d7dd4606 100644 --- a/mrbgems/mruby-eval/test/eval.rb +++ b/mrbgems/mruby-eval/test/eval.rb @@ -34,7 +34,7 @@ assert('Kernel.eval', '15.3.1.2.3') do } assert_equal(2) { a = 10 - Kernel.eval 'def f(a); b=a.send(:+, 1); end' + Kernel.eval 'def f(a); b=a+1; end' f(1) } end diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 18003ef4d..25c153cee 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -680,6 +680,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb) mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 587d00d6f..748fe9c6c 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -1,3 +1,30 @@ +assert('Kernel#__send__', '15.3.1.3.4') do + # test with block + l = __send__(:lambda) do + true + end + + assert_true l.call + assert_equal Proc, l.class + # test with argument + assert_true __send__(:respond_to?, :nil?) + # test without argument and without block + assert_equal String, __send__(:to_s).class +end + +assert('Kernel#send', '15.3.1.3.44') do + # test with block + l = send(:lambda) do + true + end + + assert_true l.call + assert_equal l.class, Proc + # test with argument + assert_true send(:respond_to?, :nil?) + # test without argument and without block + assert_equal send(:to_s).class, String +end assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do o = Object.new diff --git a/mrbgems/mruby-method/test/method.rb b/mrbgems/mruby-method/test/method.rb index eb5f48341..9fd6a558e 100644 --- a/mrbgems/mruby-method/test/method.rb +++ b/mrbgems/mruby-method/test/method.rb @@ -102,10 +102,7 @@ end assert 'Method#call for regression' do obj = BasicObject.new - def obj.foo - :ok - end - assert_equal :ok, Kernel.instance_method(:send).bind(obj).call(:foo), "https://github.com/ksss/mruby-method/issues/4" + assert_equal String, Kernel.instance_method(:inspect).bind(obj).call().class, "https://github.com/ksss/mruby-method/issues/4" end assert 'Method#call with undefined method' do diff --git a/src/kernel.c b/src/kernel.c index 248fa5266..db681d510 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -869,7 +869,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */ mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */ mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ - mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ diff --git a/test/t/codegen.rb b/test/t/codegen.rb index 154d44168..acb9e1bf5 100644 --- a/test/t/codegen.rb +++ b/test/t/codegen.rb @@ -184,14 +184,14 @@ assert('register window of calls (#3783)') do # NODE_UNDEF assert_nothing_raised do class << Object.new - undef send + undef inspect end end # NODE_ALIAS assert_nothing_raised do class << Object.new - alias send2 send + alias inspect2 inspect end end end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 9744bddba..a730bdb24 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -92,20 +92,6 @@ assert('Kernel#__id__', '15.3.1.3.3') do assert_equal Fixnum, __id__.class end -assert('Kernel#__send__', '15.3.1.3.4') do - # test with block - l = __send__(:lambda) do - true - end - - assert_true l.call - assert_equal Proc, l.class - # test with argument - assert_true __send__(:respond_to?, :nil?) - # test without argument and without block - assert_equal String, __send__(:to_s).class -end - assert('Kernel#block_given?', '15.3.1.3.6') do def bg_try(&b) if block_given? @@ -440,20 +426,6 @@ assert('Kernel#respond_to?', '15.3.1.3.43') do assert_false Test4RespondTo.new.respond_to?(:test_method) end -assert('Kernel#send', '15.3.1.3.44') do - # test with block - l = send(:lambda) do - true - end - - assert_true l.call - assert_equal l.class, Proc - # test with argument - assert_true send(:respond_to?, :nil?) - # test without argument and without block - assert_equal send(:to_s).class, String -end - assert('Kernel#to_s', '15.3.1.3.46') do assert_equal to_s.class, String end diff --git a/test/t/module.rb b/test/t/module.rb index fda375721..78cb5d07f 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -536,61 +536,61 @@ end #end # mruby has no visibility control - assert 'Module#prepend visibility' do - bug8005 = '[ruby-core:53106] [Bug #8005]' - c = Class.new do - prepend Module.new {} - def foo() end - protected :foo - end - a = c.new - assert_true a.respond_to?(:foo), bug8005 - assert_nothing_raised(bug8005) {a.send :foo} - end + # assert 'Module#prepend visibility' do + # bug8005 = '[ruby-core:53106] [Bug #8005]' + # c = Class.new do + # prepend Module.new {} + # def foo() end + # protected :foo + # end + # a = c.new + # assert_true a.respond_to?(:foo), bug8005 + # assert_nothing_raised(bug8005) {a.send :foo} + # end # mruby has no visibility control - assert 'Module#prepend inherited visibility' do - bug8238 = '[ruby-core:54105] [Bug #8238]' - module Test4PrependVisibilityInherited - class A - def foo() A; end - private :foo - end - class B < A - public :foo - prepend Module.new - end - end - assert_equal(Test4PrependVisibilityInherited::A, Test4PrependVisibilityInherited::B.new.foo, "#{bug8238}") - end - - assert 'Module#prepend super in alias' do - skip "super does not currently work in aliased methods" - bug7842 = '[Bug #7842]' - - p = labeled_module("P") do - def m; "P"+super; end - end - - a = labeled_class("A") do - def m; "A"; end - end - - b = labeled_class("B", a) do - def m; "B"+super; end - alias m2 m - prepend p - alias m3 m - end - - assert_nothing_raised do - assert_equal("BA", b.new.m2, bug7842) - end - - assert_nothing_raised do - assert_equal("PBA", b.new.m3, bug7842) - end - end + # assert 'Module#prepend inherited visibility' do + # bug8238 = '[ruby-core:54105] [Bug #8238]' + # module Test4PrependVisibilityInherited + # class A + # def foo() A; end + # private :foo + # end + # class B < A + # public :foo + # prepend Module.new + # end + # end + # assert_equal(Test4PrependVisibilityInherited::A, Test4PrependVisibilityInherited::B.new.foo, "#{bug8238}") + # end + + # assert 'Module#prepend super in alias' do + # skip "super does not currently work in aliased methods" + # bug7842 = '[Bug #7842]' + + # p = labeled_module("P") do + # def m; "P"+super; end + # end + + # a = labeled_class("A") do + # def m; "A"; end + # end + + # b = labeled_class("B", a) do + # def m; "B"+super; end + # alias m2 m + # prepend p + # alias m3 m + # end + + # assert_nothing_raised do + # assert_equal("BA", b.new.m2, bug7842) + # end + + # assert_nothing_raised do + # assert_equal("PBA", b.new.m3, bug7842) + # end + # end assert 'Module#prepend each class' do m = labeled_module("M") -- cgit v1.2.3 From a657117e4e5fbde4434661794f80a93dde55d70d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 1 Sep 2018 17:36:35 +0900 Subject: Avoid warning in MSVC compilation. --- mrbgems/mruby-compiler/core/codegen.c | 6 +++--- mrbgems/mruby-socket/test/sockettest.c | 1 + src/vm.c | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index efd20d908..98b215f6b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2378,9 +2378,9 @@ codegen(codegen_scope *s, node *tree, int val) #endif { if (i == -1) genop_1(s, OP_LOADI__1, cursp()); - else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), -i); - else if (i < 8) genop_1(s, OP_LOADI_0 + i, cursp()); - else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), i); + else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i); + else if (i < 8) genop_1(s, OP_LOADI_0 + (uint8_t)i, cursp()); + else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), (uint16_t)i); else { int off = new_lit(s, mrb_fixnum_value(i)); genop_2(s, OP_LOADL, cursp(), off); diff --git a/mrbgems/mruby-socket/test/sockettest.c b/mrbgems/mruby-socket/test/sockettest.c index 086bc4892..3017c7cc1 100644 --- a/mrbgems/mruby-socket/test/sockettest.c +++ b/mrbgems/mruby-socket/test/sockettest.c @@ -12,6 +12,7 @@ #include #include +#define open _open #define close _close #define unlink _unlink diff --git a/src/vm.c b/src/vm.c index 77d9316d4..70c27da57 100644 --- a/src/vm.c +++ b/src/vm.c @@ -176,7 +176,7 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t oldsize /** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end */ static void -stack_extend_alloc(mrb_state *mrb, int room) +stack_extend_alloc(mrb_state *mrb, mrb_int room) { mrb_value *oldbase = mrb->c->stbase; mrb_value *newstack; @@ -333,7 +333,7 @@ ecall(mrb_state *mrb) struct REnv *env; ptrdiff_t cioff; int ai = mrb_gc_arena_save(mrb); - uint8_t i = --c->eidx; + uint16_t i = --c->eidx; int nregs; if (i<0) return; -- cgit v1.2.3 From c2634e18b6dc8bf2b447e6f18699e3f4ed6f9474 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 3 Sep 2018 15:15:49 +0900 Subject: Add type casts to silence MSVC warnings. --- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 2 +- src/vm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 5c2b58da5..1880f22f7 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -111,7 +111,7 @@ p(mrb_state *mrb, mrb_value obj, int prompt) if (!mrb_string_p(val)) { val = mrb_obj_as_string(mrb, obj); } - msg = mrb_locale_from_utf8(RSTRING_PTR(val), RSTRING_LEN(val)); + msg = mrb_locale_from_utf8(RSTRING_PTR(val), (int)RSTRING_LEN(val)); fwrite(msg, strlen(msg), 1, stdout); mrb_locale_free(msg); putc('\n', stdout); diff --git a/src/vm.c b/src/vm.c index 70c27da57..43c3d120f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -186,7 +186,7 @@ stack_extend_alloc(mrb_state *mrb, mrb_int room) if (off > size) size = off; #ifdef MRB_STACK_EXTEND_DOUBLING - if (room <= size) + if (room <= (size_t)size) size *= 2; else size += room; -- cgit v1.2.3 From 7592dfcf7dfabc5d5df26906d6571d4f61aa8de7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 4 Sep 2018 20:50:54 +0900 Subject: Need more precise constant name check. This change was inspired by [ruby-bugs#7573] --- src/class.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index e074cbc3b..22fe36fb3 100644 --- a/src/class.c +++ b/src/class.c @@ -1981,7 +1981,14 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) end = (end == -1) ? len : end; id = mrb_intern(mrb, ptr+off, end-off); mod = mrb_const_get_sym(mrb, mod, id); - off = (end == len) ? end : end+2; + if (end == len) + off = end; + else { + off = end + 2; + if (off == len) { /* trailing "::" */ + mrb_name_error(mrb, id, "wrong constant name '%S'", path); + } + } } return mod; -- cgit v1.2.3 From 9b5910bd0f674f5948cd1185e07d8a024477d162 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 4 Sep 2018 21:06:36 +0900 Subject: Revert "Remove top-level constant lookup; CRuby2.5"; fix #4070 This reverts commit c96def7c96c50f3b8e22e47ce31a6c5a37939dfd. This change was from my misunderstanding. --- src/variable.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index e753f8d29..00bdb4b8d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -732,24 +732,23 @@ mod_const_check(mrb_state *mrb, mrb_value mod) } static mrb_value -const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool top) +const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) { struct RClass *c = base; mrb_value v; mrb_bool retry = FALSE; mrb_value name; - struct RClass *oclass = mrb->object_class; L_RETRY: while (c) { - if (top || c != oclass || base == oclass) { + if (c->iv) { if (iv_get(mrb, c->iv, sym, &v)) return v; } c = c->super; } if (!retry && base->tt == MRB_TT_MODULE) { - c = oclass; + c = mrb->object_class; retry = TRUE; goto L_RETRY; } @@ -761,7 +760,7 @@ MRB_API mrb_value mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) { mod_const_check(mrb, mod); - return const_get(mrb, mrb_class_ptr(mod), sym, FALSE); + return const_get(mrb, mrb_class_ptr(mod), sym); } mrb_value @@ -796,7 +795,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) } proc = proc->upper; } - return const_get(mrb, c, sym, TRUE); + return const_get(mrb, c, sym); } MRB_API void -- cgit v1.2.3 From 2a9525caabeab6a8d6cd54889d4a2b82505abb20 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 5 Sep 2018 07:06:25 +0900 Subject: Add `argv` and `argc` check in `OP_ENTER`; fix #4102 `argv` may be retrieved from an array whose `ptr` is `NULL` when it`s empty. --- src/vm.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 43c3d120f..9c4580fb3 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1791,21 +1791,19 @@ RETRY_TRY_BLOCK: kargs = 0; } else { - if (!mrb_hash_p(argv[argc - 1])) { - if (r) { - kdict = mrb_hash_new(mrb); - kargs = 0; - } - else { - mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); - mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); - goto L_RAISE; - } + if (argv && argc > 0 && mrb_hash_p(argv[argc-1])) { + kdict = argv[argc-1]; + mrb_hash_check_kdict(mrb, kdict); + } + else if (r) { + kdict = mrb_hash_new(mrb); + kargs = 0; } else { - kdict = argv[argc-1]; + mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); + mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + goto L_RAISE; } - mrb_hash_check_kdict(mrb, kdict); if (MRB_ASPEC_KEY(a) > 0) { kdict = mrb_hash_dup(mrb, kdict); } -- cgit v1.2.3 From 0b44e802a95101bb7c5849382d669cf6cf4f2680 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 6 Sep 2018 23:30:32 +0900 Subject: Need to check if merging hash is empty; fix #4107 --- src/hash.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 7d81bc343..f6b61f4e1 100644 --- a/src/hash.c +++ b/src/hash.c @@ -969,6 +969,7 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) h1 = RHASH_TBL(hash1); h2 = RHASH_TBL(hash2); + if (!h2) return; if (!h1) { RHASH_TBL(hash1) = kh_copy(ht, mrb, h2); return; -- cgit v1.2.3 From 2a24b40d300b1e0072a4a0f7de43b126479bc390 Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 5 Sep 2018 22:13:46 +0900 Subject: Not set a class/module name into anonymous class/module --- src/variable.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 00bdb4b8d..4bb3e4bef 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1069,8 +1069,10 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) str = mrb_sym2name_len(mrb, name, &len); mrb_str_cat(mrb, path, str, len); - iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); - iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); - mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + if (RSTRING_PTR(path)[0] != '#') { + iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); + iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); + mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + } return path; } -- cgit v1.2.3 From fd57af3ea4628dbb688e4380b12ac2bb06de4f5f Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 5 Sep 2018 20:09:30 +0900 Subject: Undesirable line split --- src/class.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 22fe36fb3..76c699881 100644 --- a/src/class.c +++ b/src/class.c @@ -2254,8 +2254,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4 -.34 */ + mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 9b0ef58a48aced26538f3f9ed2490ce34e2e5840 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 6 Sep 2018 00:09:49 +0900 Subject: A class/module name is now defined for meta programing --- src/variable.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 4bb3e4bef..a2d002892 100644 --- a/src/variable.c +++ b/src/variable.c @@ -344,6 +344,8 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } +static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); + MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { @@ -352,6 +354,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } + assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); } @@ -360,6 +363,36 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } +static inline mrb_bool +is_namespace(enum mrb_vtype tt) +{ + return tt == MRB_TT_CLASS || tt == MRB_TT_MODULE ? TRUE : FALSE; +} + +static inline void +assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + if (is_namespace(obj->tt) && is_namespace(mrb_type(v)) && ISUPPER(mrb_sym2name(mrb, sym)[0])) { + struct RObject *c = mrb_obj_ptr(v); + mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); + mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); + + if (mrb_nil_p(o)) { + mrb_sym id_outer = mrb_intern_lit(mrb, "__outer__"); + o = mrb_obj_iv_get(mrb, c, id_outer); + + if (mrb_nil_p(o)) { + if ((struct RClass *)obj == mrb->object_class) { + mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + } + else { + mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + } + } + } + } +} + MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) { -- cgit v1.2.3 From 1595e8368a561680f8472f2e9f5fb363dcb135b4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Sep 2018 00:02:46 +0900 Subject: Fix indent --- src/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 5e1f9f561..6b4c7200c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -387,8 +387,8 @@ id: switch (*m) { case '!': case '?': case '=': ++m; default: break; - } } + } break; } return *m ? FALSE : TRUE; -- cgit v1.2.3 From 1997fcf98f596f6af2bf1d20ccde1b1abfe7324d Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Sep 2018 22:00:18 +0900 Subject: Add MRB_IMPROVE_META_PROGRAMMING configuration --- include/mrbconf.h | 3 +++ src/variable.c | 10 ++++++++++ 2 files changed, 13 insertions(+) (limited to 'src') diff --git a/include/mrbconf.h b/include/mrbconf.h index cc28acfaa..379386896 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -110,6 +110,9 @@ /* fixed size state atexit stack */ //#define MRB_FIXED_STATE_ATEXIT_STACK +/* improve meta programming support */ +//#define MRB_IMPROVE_META_PROGRAMMING + /* -DMRB_DISABLE_XXXX to drop following features */ //#define MRB_DISABLE_STDIO /* use of stdio */ diff --git a/src/variable.c b/src/variable.c index a2d002892..047c96e8a 100644 --- a/src/variable.c +++ b/src/variable.c @@ -344,7 +344,9 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } +#ifdef MRB_IMPROVE_META_PROGRAMMING static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); +#endif MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) @@ -354,7 +356,9 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } +#ifdef MRB_IMPROVE_META_PROGRAMMING assign_class_name(mrb, obj, sym, v); +#endif if (!obj->iv) { obj->iv = iv_new(mrb); } @@ -363,6 +367,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } +#ifdef MRB_IMPROVE_META_PROGRAMMING static inline mrb_bool is_namespace(enum mrb_vtype tt) { @@ -392,6 +397,7 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) } } } +#endif MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) @@ -1102,10 +1108,14 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) str = mrb_sym2name_len(mrb, name, &len); mrb_str_cat(mrb, path, str, len); +#ifdef MRB_IMPROVE_META_PROGRAMMING if (RSTRING_PTR(path)[0] != '#') { +#endif iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); +#ifdef MRB_IMPROVE_META_PROGRAMMING } +#endif return path; } -- cgit v1.2.3 From 366848996a6cce8e733246bce6c3f76d797003bb Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Sep 2018 00:22:36 +0900 Subject: Clear terminated space --- examples/targets/build_config_android_arm64-v8a.rb | 4 ++-- examples/targets/build_config_android_armeabi.rb | 4 ++-- mrbgems/mruby-array-ext/test/array.rb | 2 +- mrbgems/mruby-compiler/core/codegen.c | 8 ++++---- mrbgems/mruby-random/src/random.c | 2 +- src/array.c | 2 +- src/codedump.c | 2 +- src/gc.c | 2 +- src/numeric.c | 2 +- src/variable.c | 10 +++++----- src/vm.c | 4 ++-- tasks/toolchains/gcc.rake | 2 +- test/t/kernel.rb | 2 +- test/t/syntax.rb | 6 +++--- 14 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/examples/targets/build_config_android_arm64-v8a.rb b/examples/targets/build_config_android_arm64-v8a.rb index 6188c13ec..70b0f4b97 100644 --- a/examples/targets/build_config_android_arm64-v8a.rb +++ b/examples/targets/build_config_android_arm64-v8a.rb @@ -15,8 +15,8 @@ end # Requires Android NDK r13 or later. MRuby::CrossBuild.new('android-arm64-v8a') do |conf| - params = { - :arch => 'arm64-v8a', + params = { + :arch => 'arm64-v8a', :platform => 'android-24', :toolchain => :clang, } diff --git a/examples/targets/build_config_android_armeabi.rb b/examples/targets/build_config_android_armeabi.rb index b7eb33a92..17330242a 100644 --- a/examples/targets/build_config_android_armeabi.rb +++ b/examples/targets/build_config_android_armeabi.rb @@ -15,8 +15,8 @@ end # Requires Android NDK r13 or later. MRuby::CrossBuild.new('android-armeabi') do |conf| - params = { - :arch => 'armeabi', + params = { + :arch => 'armeabi', :platform => 'android-24', :toolchain => :clang, } diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index 7d810acc2..4f54c65c3 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -418,5 +418,5 @@ assert('Array#transpose') do assert_equal([[1], [2], [3]].transpose, [[1,2,3]]) assert_equal([[1,2], [3,4], [5,6]].transpose, [[1,3,5], [2,4,6]]) assert_raise(TypeError) { [1].transpose } - assert_raise(IndexError) { [[1], [2,3,4]].transpose } + assert_raise(IndexError) { [[1], [2,3,4]].transpose } end diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 8be9a8ebe..74504ffd1 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -419,7 +419,7 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) } else { struct mrb_insn_data data = mrb_last_insn(s); - + switch (data.insn) { case OP_MOVE: if (dst == src) return; /* remove useless MOVE */ @@ -456,7 +456,7 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src) } else { struct mrb_insn_data data = mrb_last_insn(s); - + if (data.insn == OP_MOVE && src == data.a) { s->pc = s->lastpc; genop_1(s, op, data.b); @@ -764,7 +764,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) kd = tail && tail->cdr->cdr->car? 1 : 0; /* block argument? */ ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0; - + if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) { codegen_error(s, "too many formal arguments"); } @@ -3118,7 +3118,7 @@ generate_code(mrb_state *mrb, parser_state *p, int val) scope->filename_index = p->current_filename_index; MRB_TRY(&scope->jmp) { - mrb->jmp = &scope->jmp; + mrb->jmp = &scope->jmp; /* prepare irep */ codegen(scope, p->tree, val); proc = mrb_proc_new(mrb, scope->irep); diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index b865244cc..5b926a228 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -219,7 +219,7 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) mrb_int j; mrb_value *ptr = RARRAY_PTR(ary); mrb_value tmp; - + j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary)))); diff --git a/src/array.c b/src/array.c index 2152e292d..f0c32bc7f 100644 --- a/src/array.c +++ b/src/array.c @@ -231,7 +231,7 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) static void ary_shrink_capa(mrb_state *mrb, struct RArray *a) { - + mrb_int capa; if (ARY_EMBED_P(a)) return; diff --git a/src/codedump.c b/src/codedump.c index 454b16b36..30a14f937 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -516,7 +516,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) #undef OPCODE } break; - + default: printf("OP_unknown (0x%x)\n", ins); break; diff --git a/src/gc.c b/src/gc.c index 9858e45fc..e429603dd 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1559,7 +1559,7 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo mrb->jmp = &c_jmp; gc_each_objects(mrb, &mrb->gc, callback, data); mrb->jmp = prev_jmp; - mrb->gc.iterating = iterating; + mrb->gc.iterating = iterating; } MRB_CATCH(&c_jmp) { mrb->gc.iterating = iterating; mrb->jmp = prev_jmp; diff --git a/src/numeric.c b/src/numeric.c index c3e7d77a3..f7f0318e8 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -433,7 +433,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) val = trunc(val); #else if (val > 0){ - val = floor(val); + val = floor(val); } else { val = ceil(val); } diff --git a/src/variable.c b/src/variable.c index 00bdb4b8d..506b4b63e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -790,7 +790,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) proc = mrb->c->ci->proc; while (proc) { c2 = MRB_PROC_TARGET_CLASS(proc); - if (c2 && iv_get(mrb, c2->iv, sym, &v)) { + if (c2 && iv_get(mrb, c2->iv, sym, &v)) { return v; } proc = proc->upper; @@ -988,25 +988,25 @@ struct csym_arg { struct RClass *c; mrb_sym sym; }; - + static int csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { struct csym_arg *a = (struct csym_arg*)p; struct RClass *c = a->c; - + if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) { a->sym = sym; return 1; /* stop iteration */ } return 0; } - + static mrb_sym find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c) { struct csym_arg arg; - + if (!outer) return 0; if (outer == c) return 0; arg.c = c; diff --git a/src/vm.c b/src/vm.c index 9c4580fb3..14c42984e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1818,7 +1818,7 @@ RETRY_TRY_BLOCK: } regs[blk_pos] = *blk; /* move block */ if (kd) regs[len + 1] = kdict; - + /* copy mandatory and optional arguments */ if (argv0 != argv) { value_move(®s[1], argv, argc-mlen); /* m1 + o */ @@ -2077,7 +2077,7 @@ RETRY_TRY_BLOCK: break; case OP_R_BREAK: if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN; - if (MRB_PROC_ORPHAN_P(proc)) { + if (MRB_PROC_ORPHAN_P(proc)) { mrb_value exc; L_BREAK_ERROR: diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake index fc2e0bff3..e0eb36f26 100644 --- a/tasks/toolchains/gcc.rake +++ b/tasks/toolchains/gcc.rake @@ -55,7 +55,7 @@ MRuby::Toolchain.new(:gcc) do |conf, _params| @header_search_paths end end - + def conf.enable_sanitizer(*opts) fail 'sanitizer already set' if @sanitizer_list diff --git a/test/t/kernel.rb b/test/t/kernel.rb index a730bdb24..74176fbd0 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -157,7 +157,7 @@ assert('Kernel#clone', '15.3.1.3.8') do assert_true a.respond_to?(:test) assert_false b.respond_to?(:test) assert_true c.respond_to?(:test) - + a.freeze d = a.clone assert_true d.frozen? diff --git a/test/t/syntax.rb b/test/t/syntax.rb index c5405aa9c..883cbd1ba 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -454,15 +454,15 @@ assert('multiline comments work correctly') do =begin this is a comment with nothing after begin and end =end -=begin this is a comment +=begin this is a comment this is a comment with extra after =begin =end =begin this is a comment that has =end with spaces after it -=end +=end =begin this is a comment this is a comment that has extra after =begin and =end with spaces after it -=end +=end line = __LINE__ =begin this is a comment this is a comment that has extra after =begin and =end with tabs after it -- cgit v1.2.3 From 5e6cd86f6eedea213fbeb5f1e7a5aa0ab303036a Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Sep 2018 23:56:06 +0900 Subject: Fix to not define outer when outer is itself. example: a = Class.new a::A = a --- src/class.c | 2 +- src/variable.c | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 22fe36fb3..96d32b4c5 100644 --- a/src/class.c +++ b/src/class.c @@ -65,7 +65,7 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb else { name = mrb_class_path(mrb, outer); if (mrb_nil_p(name)) { /* unnamed outer class */ - if (outer != mrb->object_class) { + if (outer != mrb->object_class && outer != c) { mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), mrb_obj_value(outer)); } diff --git a/src/variable.c b/src/variable.c index 047c96e8a..20edd56e4 100644 --- a/src/variable.c +++ b/src/variable.c @@ -377,21 +377,23 @@ is_namespace(enum mrb_vtype tt) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - if (is_namespace(obj->tt) && is_namespace(mrb_type(v)) && ISUPPER(mrb_sym2name(mrb, sym)[0])) { + if (is_namespace(obj->tt) && is_namespace(mrb_type(v))) { struct RObject *c = mrb_obj_ptr(v); - mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); - mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); - - if (mrb_nil_p(o)) { - mrb_sym id_outer = mrb_intern_lit(mrb, "__outer__"); - o = mrb_obj_iv_get(mrb, c, id_outer); + if (obj != c && ISUPPER(mrb_sym2name(mrb, sym)[0])) { + mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); + mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); if (mrb_nil_p(o)) { - if ((struct RClass *)obj == mrb->object_class) { - mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); - } - else { - mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + mrb_sym id_outer = mrb_intern_lit(mrb, "__outer__"); + o = mrb_obj_iv_get(mrb, c, id_outer); + + if (mrb_nil_p(o)) { + if ((struct RClass *)obj == mrb->object_class) { + mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + } + else { + mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + } } } } -- cgit v1.2.3 From 292ea06d4d10ca12ec931c73f0ca39db23d66b8e Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 8 Sep 2018 10:06:09 +0900 Subject: Fix outer module name example: a = Module.new a::B = Module.new p [a, a::B] # => [#, #::B] # => [#, #::B] (Fixed) --- src/class.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 22fe36fb3..046090515 100644 --- a/src/class.c +++ b/src/class.c @@ -1701,7 +1701,8 @@ mrb_class_name(mrb_state *mrb, struct RClass* c) { mrb_value path = mrb_class_path(mrb, c); if (mrb_nil_p(path)) { - path = mrb_str_new_lit(mrb, "#tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#"); } -- cgit v1.2.3 From e9b1d9dc2f1de290da4aadfd39f1957502d67e18 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Sep 2018 23:52:14 +0900 Subject: Array size may be changed in `mrb_get_args()` reentry. fix #4116; fix #4117; fix #4118; fix #4119; fix #4120 --- mrbgems/mruby-array-ext/src/array.c | 5 +++-- src/array.c | 22 ++++++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index 169f968f9..792eb26de 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -175,7 +175,7 @@ static mrb_value mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int i, j, k, len, alen = ARY_LEN(a); + mrb_int i, j, k, len, alen; mrb_value val; mrb_value *ptr; mrb_value ary; @@ -188,7 +188,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "o|i", &index, &len); switch (mrb_type(index)) { case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { goto delete_pos_len; } else { @@ -205,6 +205,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "ii", &i, &len); delete_pos_len: + alen = ARY_LEN(a); if (i < 0) i += alen; if (i < 0 || alen < i) return mrb_nil_value(); if (len < 0) return mrb_nil_value(); diff --git a/src/array.c b/src/array.c index f0c32bc7f..0b039a6ec 100644 --- a/src/array.c +++ b/src/array.c @@ -853,14 +853,14 @@ static mrb_value mrb_ary_aget(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int i, len, alen = ARY_LEN(a); + mrb_int i, len, alen; mrb_value index; if (mrb_get_args(mrb, "o|i", &index, &len) == 1) { switch (mrb_type(index)) { /* a[n..m] */ case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { return ary_subseq(mrb, a, i, len); } else { @@ -874,6 +874,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self) } i = aget_index(mrb, index); + alen = ARY_LEN(a); if (i < 0) i += alen; if (i < 0 || alen < i) return mrb_nil_value(); if (len < 0) return mrb_nil_value(); @@ -953,9 +954,10 @@ mrb_ary_delete_at(mrb_state *mrb, mrb_value self) mrb_int index; mrb_value val; mrb_value *ptr; - mrb_int len, alen = ARY_LEN(a); + mrb_int len, alen; mrb_get_args(mrb, "i", &index); + alen = ARY_LEN(a); if (index < 0) index += alen; if (index < 0 || alen <= index) return mrb_nil_value(); @@ -980,16 +982,17 @@ static mrb_value mrb_ary_first(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int size, alen = ARY_LEN(a); + mrb_int size, alen; if (mrb_get_argc(mrb) == 0) { - return (alen > 0)? ARY_PTR(a)[0]: mrb_nil_value(); + return (ARY_LEN(a) > 0)? ARY_PTR(a)[0]: mrb_nil_value(); } mrb_get_args(mrb, "|i", &size); if (size < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); } + alen = ARY_LEN(a); if (size > alen) size = alen; if (ARY_SHARED_P(a)) { return ary_subseq(mrb, a, 0, size); @@ -1001,10 +1004,13 @@ static mrb_value mrb_ary_last(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_int size, alen = ARY_LEN(a); + mrb_int n, size, alen; - if (mrb_get_args(mrb, "|i", &size) == 0) - return (alen > 0)? ARY_PTR(a)[alen - 1]: mrb_nil_value(); + n = mrb_get_args(mrb, "|i", &size); + alen = ARY_LEN(a); + if (n == 0) { + return (alen > 0) ? ARY_PTR(a)[alen - 1]: mrb_nil_value(); + } if (size < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); -- cgit v1.2.3 From 505e6017306e09487a4a7f1b0fb1c9976f4f5ec5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 13:53:55 +0900 Subject: Revert "Add MRB_IMPROVE_META_PROGRAMMING configuration" This reverts commit 1997fcf98f596f6af2bf1d20ccde1b1abfe7324d. It became the default behavior. --- include/mrbconf.h | 3 --- src/variable.c | 10 ---------- 2 files changed, 13 deletions(-) (limited to 'src') diff --git a/include/mrbconf.h b/include/mrbconf.h index 379386896..cc28acfaa 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -110,9 +110,6 @@ /* fixed size state atexit stack */ //#define MRB_FIXED_STATE_ATEXIT_STACK -/* improve meta programming support */ -//#define MRB_IMPROVE_META_PROGRAMMING - /* -DMRB_DISABLE_XXXX to drop following features */ //#define MRB_DISABLE_STDIO /* use of stdio */ diff --git a/src/variable.c b/src/variable.c index 01077a34e..cc7936a46 100644 --- a/src/variable.c +++ b/src/variable.c @@ -344,9 +344,7 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } -#ifdef MRB_IMPROVE_META_PROGRAMMING static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -#endif MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) @@ -356,9 +354,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (MRB_FROZEN_P(obj)) { mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); } -#ifdef MRB_IMPROVE_META_PROGRAMMING assign_class_name(mrb, obj, sym, v); -#endif if (!obj->iv) { obj->iv = iv_new(mrb); } @@ -367,7 +363,6 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } -#ifdef MRB_IMPROVE_META_PROGRAMMING static inline mrb_bool is_namespace(enum mrb_vtype tt) { @@ -399,7 +394,6 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) } } } -#endif MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) @@ -1110,14 +1104,10 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) str = mrb_sym2name_len(mrb, name, &len); mrb_str_cat(mrb, path, str, len); -#ifdef MRB_IMPROVE_META_PROGRAMMING if (RSTRING_PTR(path)[0] != '#') { -#endif iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); -#ifdef MRB_IMPROVE_META_PROGRAMMING } -#endif return path; } -- cgit v1.2.3 From 159575f63024c79592229f9c0e7da42a0075dae9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 20 Sep 2018 13:57:43 +0900 Subject: Renamed `is_namespace()` to `namespace_p()`. --- src/variable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index cc7936a46..72c13aa1f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -364,7 +364,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) } static inline mrb_bool -is_namespace(enum mrb_vtype tt) +namespace_p(enum mrb_vtype tt) { return tt == MRB_TT_CLASS || tt == MRB_TT_MODULE ? TRUE : FALSE; } @@ -372,7 +372,7 @@ is_namespace(enum mrb_vtype tt) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - if (is_namespace(obj->tt) && is_namespace(mrb_type(v))) { + if (namespace_p(obj->tt) && namespace_p(mrb_type(v))) { struct RObject *c = mrb_obj_ptr(v); if (obj != c && ISUPPER(mrb_sym2name(mrb, sym)[0])) { mrb_sym id_classname = mrb_intern_lit(mrb, "__classname__"); -- cgit v1.2.3 From 9bd2a3b5d9f56d838a25e2038f948afdc4adccac Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Sep 2018 00:49:40 +0900 Subject: Fixed a top-level local variable bug in `mirb`. `OP_STOP` returned a wrong value. --- src/vm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 14c42984e..0192fc907 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2056,6 +2056,7 @@ RETRY_TRY_BLOCK: struct mrb_context *c; if (!mrb->c->prev) { /* toplevel return */ + regs[irep->nlocals] = v; goto L_STOP; } if (mrb->c->prev->ci == mrb->c->prev->cibase) { -- cgit v1.2.3 From 8fc56f062e40ce9eaaa61ab917cfccc2c23989d1 Mon Sep 17 00:00:00 2001 From: sbsoftware Date: Fri, 21 Sep 2018 04:22:53 +0200 Subject: Add compiler flag to disable direct threading (#4075) * Add option to disable direct threading * Prepend MRB_ to option name --- src/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 0192fc907..cba6c3924 100644 --- a/src/vm.c +++ b/src/vm.c @@ -927,10 +927,11 @@ argnum_error(mrb_state *mrb, mrb_int num) #define BYTECODE_DECODER(x) (x) #endif - +#ifndef MRB_DISABLE_DIRECT_THREADING #if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER #define DIRECT_THREADED #endif +#endif /* ifndef MRB_DISABLE_DIRECT_THREADING */ #ifndef DIRECT_THREADED -- cgit v1.2.3 From 78195eb2aeb6dbb9eea7d10cd4d5ac7caaa1bab7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 21 Sep 2018 10:27:09 +0900 Subject: Small refactoring in vm.c --- src/vm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index cba6c3924..9eeb388fc 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2054,22 +2054,21 @@ RETRY_TRY_BLOCK: case OP_R_NORMAL: NORMAL_RETURN: if (ci == mrb->c->cibase) { - struct mrb_context *c; + struct mrb_context *c = mrb->c; - if (!mrb->c->prev) { /* toplevel return */ + if (!c->prev) { /* toplevel return */ regs[irep->nlocals] = v; goto L_STOP; } - if (mrb->c->prev->ci == mrb->c->prev->cibase) { + if (c->prev->ci == c->prev->cibase) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); mrb_exc_set(mrb, exc); goto L_RAISE; } - while (mrb->c->eidx > 0) { + while (c->eidx > 0) { ecall(mrb); } /* automatic yield at the end */ - c = mrb->c; c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; -- cgit v1.2.3 From e8dcfe17454eb88f266f90cf31ca562e30378291 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 6 Aug 2018 16:38:38 +0900 Subject: Use segmented list to implement `Hash` [Experimental] I know it's not hash at all, but reduce memory consumption. --- include/mruby/hash.h | 5 +- src/hash.c | 634 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 400 insertions(+), 239 deletions(-) (limited to 'src') diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 449a7d4bc..dacdd9376 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -18,7 +18,7 @@ MRB_BEGIN_DECL struct RHash { MRB_OBJECT_HEADER; struct iv_tbl *iv; - struct kh_ht *ht; + struct seglist *ht; }; #define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v))) @@ -76,7 +76,7 @@ MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key); * * Equivalent to: * - * hash.hash_key?(key) ? hash[key] : def + * hash.key?(key) ? hash[key] : def * * @param mrb The mruby state reference. * @param hash The target hash. @@ -199,7 +199,6 @@ KHASH_DECLARE(ht, mrb_value, mrb_hash_value, TRUE) #define RHASH_TBL(h) (RHASH(h)->ht) #define RHASH_IFNONE(h) mrb_iv_get(mrb, (h), mrb_intern_lit(mrb, "ifnone")) #define RHASH_PROCDEFAULT(h) RHASH_IFNONE(h) -MRB_API struct kh_ht * mrb_hash_tbl(mrb_state *mrb, mrb_value hash); #define MRB_HASH_DEFAULT 1 #define MRB_HASH_PROC_DEFAULT 2 diff --git a/src/hash.c b/src/hash.c index f6b61f4e1..16d49af24 100644 --- a/src/hash.c +++ b/src/hash.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -47,7 +46,7 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) return kh_int_hash_func(mrb, h); } -static inline khint_t +static inline mrb_bool mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) { enum mrb_vtype t = mrb_type(a); @@ -89,7 +88,251 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) } } -KHASH_DEFINE (ht, mrb_value, mrb_hash_value, TRUE, mrb_hash_ht_hash_func, mrb_hash_ht_hash_equal) +/* return non zero to break the loop */ +typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key,mrb_value val, void *data); + +#ifndef MRB_SG_SEGMENT_SIZE +#define MRB_SG_SEGMENT_SIZE 5 +#endif + +typedef struct segment { + mrb_value key[MRB_SG_SEGMENT_SIZE]; + mrb_value val[MRB_SG_SEGMENT_SIZE]; + struct segment *next; +} segment; + +/* Instance variable table structure */ +typedef struct seglist { + segment *rootseg; + size_t size; + size_t last_len; +} seglist; + +/* Creates the instance variable table. */ +static seglist* +sg_new(mrb_state *mrb) +{ + seglist *t; + + t = (seglist*)mrb_malloc(mrb, sizeof(seglist)); + t->size = 0; + t->rootseg = NULL; + t->last_len = 0; + + return t; +} + +/* Set the value for the symbol in the instance variable table. */ +static void +sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +{ + segment *seg; + segment *prev = NULL; + size_t i; + + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->key[i] = key; + seg->val[i] = val; + t->last_len = i+1; + t->size++; + return; + } + if (mrb_hash_ht_hash_equal(mrb, k, key)) { + seg->val[i] = val; + return; + } + } + prev = seg; + seg = seg->next; + } + + /* Not found */ + t->size++; + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); + if (!seg) return; + seg->next = NULL; + seg->key[0] = key; + seg->val[0] = val; + t->last_len = 1; + if (prev) { + prev->next = seg; + } + else { + t->rootseg = seg; + } +} + +/* Get a value for a symbol from the instance variable table. */ +static mrb_bool +sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +{ + segment *seg; + size_t i; + + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (mrb_hash_ht_hash_equal(mrb, k, key)) { + if (vp) *vp = seg->val[i]; + return TRUE; + } + } + seg = seg->next; + } + return FALSE; +} + +/* Deletes the value for the symbol from the instance variable table. */ +static mrb_bool +sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +{ + segment *seg; + size_t i; + + if (t == NULL) return FALSE; + seg = t->rootseg; + while (seg) { + for (i=0; ikey[i]; + + if (!seg->next && i >= t->last_len) { + /* not found */ + return FALSE; + } + if (mrb_hash_ht_hash_equal(mrb, k, key)) { + segment *sg0; + size_t i0; + + t->size--; + if (vp) *vp = seg->val[i]; + sg0 = seg; + i0 = i; + while (seg) { + for (i++; inext && i >= t->last_len) { + t->last_len--; + if (t->last_len == 0 && sg0 != seg) { + sg0->next = NULL; + t->last_len = MRB_SG_SEGMENT_SIZE; + mrb_free(mrb, seg); + } + return TRUE; + } + sg0->key[i0] = seg->key[i]; + sg0->val[i0] = seg->val[i]; + i0 = i; + } + sg0 = seg; + seg = seg->next; + } + t->last_len--; + return TRUE; + } + } + seg = seg->next; + } + return FALSE; +} + +/* Iterates over the instance variable table. */ +static void +sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) +{ + segment *seg; + size_t i; + + if (t == NULL) return; + seg = t->rootseg; + while (seg) { + for (i=0; inext && i >= t->last_len) { + return; + } + if ((*func)(mrb, seg->key[i], seg->val[i], p) != 0) + return; + } + seg = seg->next; + } +} + +/* Get the size of the instance variable table. */ +static size_t +sg_size(mrb_state *mrb, seglist *t) +{ + segment *seg; + size_t size = 0; + + if (t == NULL) return 0; + if (t->size > 0) return t->size; + seg = t->rootseg; + while (seg) { + if (seg->next == NULL) { + size += t->last_len; + return size; + } + seg = seg->next; + size += MRB_SG_SEGMENT_SIZE; + } + /* empty seglist */ + return 0; +} + +/* Copy the instance variable table. */ +static seglist* +sg_copy(mrb_state *mrb, seglist *t) +{ + segment *seg; + seglist *t2; + + size_t i; + + seg = t->rootseg; + t2 = sg_new(mrb); + + while (seg != NULL) { + for (i=0; ikey[i]; + mrb_value val = seg->val[i]; + + if ((seg->next == NULL) && (i >= t->last_len)) { + return t2; + } + sg_put(mrb, t2, key, val); + } + seg = seg->next; + } + return t2; +} + +/* Free memory of the instance variable table. */ +static void +sg_free(mrb_state *mrb, seglist *t) +{ + segment *seg; + + if (!t) return; + seg = t->rootseg; + while (seg) { + segment *p = seg; + seg = seg->next; + mrb_free(mrb, p); + } + mrb_free(mrb, t); +} static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); @@ -105,57 +348,55 @@ mrb_hash_ht_key(mrb_state *mrb, mrb_value key) #define KEY(key) mrb_hash_ht_key(mrb, key) +static int +hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + mrb_gc_mark_value(mrb, key); + mrb_gc_mark_value(mrb, val); + return 0; +} + void mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash) { - khiter_t k; - khash_t(ht) *h = hash->ht; - - if (!h) return; - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_value key = kh_key(h, k); - mrb_value val = kh_value(h, k).v; - - mrb_gc_mark_value(mrb, key); - mrb_gc_mark_value(mrb, val); - } - } + sg_foreach(mrb, hash->ht, hash_mark_i, NULL); } size_t mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash) { if (!hash->ht) return 0; - return kh_size(hash->ht)*2; + return sg_size(mrb, hash->ht)*2; } void mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash) { - if (hash->ht) kh_destroy(ht, mrb, hash->ht); + sg_free(mrb, hash->ht); } - MRB_API mrb_value -mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) +mrb_hash_new(mrb_state *mrb) { struct RHash *h; h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - /* khash needs 1/4 empty space so it is not resized immediately */ - if (capa == 0) - h->ht = 0; - else - h->ht = kh_init_size(ht, mrb, (khint_t)(capa*4/3)); + h->ht = 0; h->iv = 0; return mrb_obj_value(h); } MRB_API mrb_value -mrb_hash_new(mrb_state *mrb) +mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) { - return mrb_hash_new_capa(mrb, 0); + struct RHash *h; + + h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); + /* preallocate segment list */ + h->ht = sg_new(mrb); + /* capacity ignored */ + h->iv = 0; + return mrb_obj_value(h); } static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash); @@ -166,7 +407,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) { mrb_value orig; struct RHash* copy; - khash_t(ht) *orig_h; + seglist *orig_h; mrb_value ifnone, vret; mrb_get_args(mrb, "o", &orig); @@ -177,22 +418,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = kh_init(ht, mrb); - - if (orig_h && kh_size(orig_h) > 0) { - khash_t(ht) *copy_h = copy->ht; - khiter_t k, copy_k; - - for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { - if (kh_exist(orig_h, k)) { - int ai = mrb_gc_arena_save(mrb); - copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k))); - mrb_gc_arena_restore(mrb, ai); - kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v; - kh_val(copy_h, copy_k).n = kh_size(copy_h)-1; - } - } - } + copy->ht = sg_copy(mrb, orig_h); if (MRB_RHASH_DEFAULT_P(self)) { copy->flags |= MRB_HASH_DEFAULT; @@ -208,65 +434,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) return vret; } +static int +check_kdict_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) +{ + if (!mrb_symbol_p(key)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys"); + } + return 0; +} + void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self) { - khash_t(ht) *orig_h; - khiter_t k; - int nosym = FALSE; + seglist *sg; - orig_h = RHASH_TBL(self); - if (!orig_h || kh_size(orig_h) == 0) return; - for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { - if (kh_exist(orig_h, k)) { - mrb_value key = kh_key(orig_h, k); - - if (!mrb_symbol_p(key)) nosym = TRUE; - } - } - if (nosym) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys"); - } + sg = RHASH_TBL(self); + if (!sg || sg_size(mrb, sg) == 0) return; + sg_foreach(mrb, sg, check_kdict_i, NULL); } MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value self) { struct RHash* copy; - khash_t(ht) *orig_h; + seglist *orig_h; orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = kh_init(ht, mrb); - - if (orig_h && kh_size(orig_h) > 0) { - int ai = mrb_gc_arena_save(mrb); - khash_t(ht) *copy_h = copy->ht; - khiter_t k, copy_k; - - for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) { - if (kh_exist(orig_h, k)) { - copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k))); - mrb_gc_arena_restore(mrb, ai); - kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v; - kh_val(copy_h, copy_k).n = kh_size(copy_h)-1; - } - } - } + copy->ht = orig_h ? sg_copy(mrb, orig_h) : NULL; return mrb_obj_value(copy); } +MRB_API mrb_bool +mrb_hash_has_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) +{ + if (sg_get(mrb, RHASH_TBL(hash), key, NULL)) { + return TRUE; + } + return FALSE; +} + MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + mrb_value val; mrb_sym mid; - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) - return kh_value(h, k).v; + if (sg_get(mrb, RHASH_TBL(hash), key, &val)) { + return val; } mid = mrb_intern_lit(mrb, "default"); @@ -280,15 +495,11 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) MRB_API mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + mrb_value val; - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) - return kh_value(h, k).v; + if (sg_get(mrb, RHASH_TBL(hash), key, &val)) { + return val; } - /* not found */ return def; } @@ -296,25 +507,9 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) MRB_API void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) { - khash_t(ht) *h; - khiter_t k; - int r; - mrb_hash_modify(mrb, hash); - h = RHASH_TBL(hash); - - if (!h) h = RHASH_TBL(hash) = kh_init(ht, mrb); - k = kh_put2(ht, mrb, h, key, &r); - kh_value(h, k).v = val; - - if (r != 0) { - /* expand */ - int ai = mrb_gc_arena_save(mrb); - key = kh_key(h, k) = KEY(key); - mrb_gc_arena_restore(mrb, ai); - kh_value(h, k).n = kh_size(h)-1; - } + sg_put(mrb, RHASH_TBL(hash), key, val); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val); return; @@ -332,24 +527,16 @@ mrb_check_hash_type(mrb_state *mrb, mrb_value hash) return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); } -MRB_API khash_t(ht)* -mrb_hash_tbl(mrb_state *mrb, mrb_value hash) -{ - khash_t(ht) *h = RHASH_TBL(hash); - - if (!h) { - return RHASH_TBL(hash) = kh_init(ht, mrb); - } - return h; -} - static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash"); } - mrb_hash_tbl(mrb, hash); + + if (!RHASH_TBL(hash)) { + RHASH_TBL(hash) = sg_new(mrb); + } } /* 15.2.13.4.16 */ @@ -589,23 +776,11 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_value delVal; - mrb_int n; - - if (h) { - k = kh_get(ht, mrb, h, key); - if (k != kh_end(h)) { - delVal = kh_value(h, k).v; - n = kh_value(h, k).n; - kh_del(ht, mrb, h, k); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; - if (kh_value(h, k).n > n) kh_value(h, k).n--; - } - return delVal; - } + seglist *sg = RHASH_TBL(hash); + mrb_value del_val; + + if (sg_del(mrb, sg, key, &del_val)) { + return del_val; } /* not found */ @@ -657,22 +832,14 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_shift(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_value delKey, delVal; + seglist *sg = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (h && kh_size(h) > 0) { - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; - - delKey = kh_key(h, k); - mrb_gc_protect(mrb, delKey); - delVal = mrb_hash_delete_key(mrb, hash, delKey); - mrb_gc_protect(mrb, delVal); - - return mrb_assoc_new(mrb, delKey, delVal); - } + if (sg && sg_size(mrb, sg) > 0) { + mrb_value del_key = sg->rootseg->key[0]; + mrb_value del_val = sg->rootseg->val[0]; + sg_del(mrb, sg, del_key, NULL); + return mrb_assoc_new(mrb, del_key, del_val); } if (MRB_RHASH_DEFAULT_P(hash)) { @@ -701,10 +868,13 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); + seglist *sg = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (h) kh_clear(ht, mrb, h); + if (sg) { + sg_free(mrb, sg); + RHASH_TBL(hash) = NULL; + } return hash; } @@ -754,10 +924,19 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - khash_t(ht) *h = RHASH_TBL(self); + seglist *sg = RHASH_TBL(self); - if (!h) return mrb_fixnum_value(0); - return mrb_fixnum_value(kh_size(h)); + if (!sg) return mrb_fixnum_value(0); + return mrb_fixnum_value(sg_size(mrb, sg)); +} + +MRB_API mrb_bool +mrb_hash_empty_p(mrb_state *mrb, mrb_value self) +{ + seglist *sg = RHASH_TBL(self); + + if (!sg) return TRUE; + return sg_size(mrb, sg) == 0; } /* 15.2.13.4.12 */ @@ -770,21 +949,10 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self) * {}.empty? #=> true * */ -MRB_API mrb_bool -mrb_hash_empty_p(mrb_state *mrb, mrb_value self) -{ - khash_t(ht) *h = RHASH_TBL(self); - - if (h) return kh_size(h) == 0; - return TRUE; -} - static mrb_value mrb_hash_empty_m(mrb_state *mrb, mrb_value self) { - if (mrb_hash_empty_p(mrb, self)) - return mrb_true_value(); - return mrb_false_value(); + return mrb_bool_value(mrb_hash_empty_p(mrb, self)); } /* 15.2.13.4.29 (x)*/ @@ -801,6 +969,13 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) return hash; } +static int +hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + mrb_ary_push(mrb, *(mrb_value*)p, key); + return 0; +} + /* 15.2.13.4.19 */ /* * call-seq: @@ -817,33 +992,24 @@ mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; - mrb_int end; + seglist *sg = RHASH_TBL(hash); + size_t size; mrb_value ary; - mrb_value *p; - - if (!h || kh_size(h) == 0) return mrb_ary_new(mrb); - ary = mrb_ary_new_capa(mrb, kh_size(h)); - end = kh_size(h)-1; - mrb_ary_set(mrb, ary, end, mrb_nil_value()); - p = RARRAY_PTR(ary); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_value kv = kh_key(h, k); - mrb_hash_value hv = kh_value(h, k); - - if (hv.n <= end) { - p[hv.n] = kv; - } - else { - p[end] = kv; - } - } - } + + if (!sg || (size = sg_size(mrb, sg)) == 0) + return mrb_ary_new(mrb); + ary = mrb_ary_new_capa(mrb, size); + sg_foreach(mrb, sg, hash_keys_i, (void*)&ary); return ary; } +static int +hash_vals_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + mrb_ary_push(mrb, *(mrb_value*)p, val); + return 0; +} + /* 15.2.13.4.28 */ /* * call-seq: @@ -860,19 +1026,14 @@ mrb_hash_keys(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash) { - khash_t(ht) *h = RHASH_TBL(hash); - khiter_t k; + seglist *sg = RHASH_TBL(hash); + size_t size; mrb_value ary; - if (!h) return mrb_ary_new(mrb); - ary = mrb_ary_new_capa(mrb, kh_size(h)); - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - mrb_hash_value hv = kh_value(h, k); - - mrb_ary_set(mrb, ary, hv.n, hv.v); - } - } + if (!sg || (size = sg_size(mrb, sg)) == 0) + return mrb_ary_new(mrb); + ary = mrb_ary_new_capa(mrb, size); + sg_foreach(mrb, sg, hash_vals_i, (void*)&ary); return ary; } @@ -898,13 +1059,11 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) { - khash_t(ht) *h; - khiter_t k; + seglist *sg; - h = RHASH_TBL(hash); - if (h) { - k = kh_get(ht, mrb, h, key); - return k != kh_end(h); + sg = RHASH_TBL(hash); + if (sg_get(mrb, sg, key, NULL)) { + return TRUE; } return FALSE; } @@ -920,6 +1079,23 @@ mrb_hash_has_key(mrb_state *mrb, mrb_value hash) return mrb_bool_value(key_p); } +struct has_v_arg { + mrb_bool found; + mrb_value val; +}; + +static int +hash_has_value_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) +{ + struct has_v_arg *arg = (struct has_v_arg*)p; + + if (mrb_equal(mrb, arg->val, val)) { + arg->found = TRUE; + return 1; + } + return 0; +} + /* 15.2.13.4.14 */ /* 15.2.13.4.27 */ /* @@ -939,30 +1115,28 @@ static mrb_value mrb_hash_has_value(mrb_state *mrb, mrb_value hash) { mrb_value val; - khash_t(ht) *h; - khiter_t k; - + struct has_v_arg arg; + mrb_get_args(mrb, "o", &val); - h = RHASH_TBL(hash); + arg.found = FALSE; + arg.val = val; + sg_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg); + return mrb_bool_value(arg.found); +} - if (h) { - for (k = kh_begin(h); k != kh_end(h); k++) { - if (!kh_exist(h, k)) continue; +static int +merge_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) +{ + seglist *h1 = (seglist*)data; - if (mrb_equal(mrb, kh_value(h, k).v, val)) { - return mrb_true_value(); - } - } - } - return mrb_false_value(); + sg_put(mrb, h1, key, val); + return 0; } MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) { - khash_t(ht) *h1; - khash_t(ht) *h2; - khiter_t k; + seglist *h1, *h2; mrb_hash_modify(mrb, hash1); hash2 = mrb_ensure_hash_type(mrb, hash2); @@ -971,22 +1145,10 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) if (!h2) return; if (!h1) { - RHASH_TBL(hash1) = kh_copy(ht, mrb, h2); + RHASH_TBL(hash1) = sg_copy(mrb, h2); return; } - for (k = kh_begin(h2); k != kh_end(h2); k++) { - khiter_t k1; - int r; - - if (!kh_exist(h2, k)) continue; - k1 = kh_put2(ht, mrb, h1, kh_key(h2, k), &r); - kh_value(h1, k1).v = kh_value(h2,k).v; - if (r != 0) { - /* expand */ - kh_key(h1, k1) = kh_key(h2, k); - kh_value(h1, k1).n = kh_size(h1)-1; - } - } + sg_foreach(mrb, h2, merge_i, h1); mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1)); return; } -- cgit v1.2.3 From 8ffd4e47fb1c18088e554d31e8af88881517a201 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 22 Sep 2018 23:05:52 +0900 Subject: Use `mrb_undef_value` for delete mark instead of shifting Hash entry table. That means entry table should be compacted periodically by `sg_compact()`. --- mrbgems/mruby-hash-ext/mrblib/hash.rb | 4 +- mrblib/hash.rb | 12 +-- src/hash.c | 176 ++++++++++++++++++---------------- 3 files changed, 97 insertions(+), 95 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index 61e4c890c..5bbbdf559 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -461,9 +461,9 @@ class Hash return to_enum :transform_keys! unless block self.keys.each do |k| value = self[k] - new_key = block.call(k) self.__delete(k) - self[new_key] = value + k = block.call(k) if block + self[k] = value end self end diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 96029a230..eba92ba4a 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -55,10 +55,9 @@ class Hash # ISO 15.2.13.4.8 def delete(key, &block) if block && !self.has_key?(key) - block.call(key) - else - self.__delete(key) + return block.call(key) end + self.__delete(key) end ## @@ -335,11 +334,8 @@ class Hash # h["AA"] #=> "b" # def rehash - h = {} - self.each{|k,v| - h[k] = v - } - self.replace(h) + self.size + self end end diff --git a/src/hash.c b/src/hash.c index 16d49af24..820ee5a71 100644 --- a/src/hash.c +++ b/src/hash.c @@ -96,16 +96,18 @@ typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key,mrb_value val, void * #endif typedef struct segment { - mrb_value key[MRB_SG_SEGMENT_SIZE]; - mrb_value val[MRB_SG_SEGMENT_SIZE]; struct segment *next; + struct { + mrb_value key; + mrb_value val; + } e[MRB_SG_SEGMENT_SIZE]; } segment; /* Instance variable table structure */ typedef struct seglist { segment *rootseg; - size_t size; - size_t last_len; + mrb_int size; + mrb_int last_len; } seglist; /* Creates the instance variable table. */ @@ -128,23 +130,24 @@ sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) { segment *seg; segment *prev = NULL; - size_t i; + mrb_int i; if (t == NULL) return; seg = t->rootseg; while (seg) { for (i=0; ikey[i]; + mrb_value k = seg->e[i].key; /* Found room in last segment after last_len */ if (!seg->next && i >= t->last_len) { - seg->key[i] = key; - seg->val[i] = val; + seg->e[i].key = key; + seg->e[i].val = val; t->last_len = i+1; - t->size++; + if (t->size >= 0) t->size++; return; } + if (mrb_undef_p(k)) continue; if (mrb_hash_ht_hash_equal(mrb, k, key)) { - seg->val[i] = val; + seg->e[i].val = val; return; } } @@ -153,13 +156,13 @@ sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) } /* Not found */ - t->size++; + if (t->size >= 0) t->size++; seg = (segment*)mrb_malloc(mrb, sizeof(segment)); if (!seg) return; seg->next = NULL; - seg->key[0] = key; - seg->val[0] = val; + seg->e[0].key = key; + seg->e[0].val = val; t->last_len = 1; if (prev) { prev->next = seg; @@ -174,19 +177,20 @@ static mrb_bool sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) { segment *seg; - size_t i; + mrb_int i; if (t == NULL) return FALSE; seg = t->rootseg; while (seg) { for (i=0; ikey[i]; + mrb_value k = seg->e[i].key; if (!seg->next && i >= t->last_len) { return FALSE; } + if (mrb_undef_p(k)) continue; if (mrb_hash_ht_hash_equal(mrb, k, key)) { - if (vp) *vp = seg->val[i]; + if (vp) *vp = seg->e[i].val; return TRUE; } } @@ -195,50 +199,81 @@ sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) return FALSE; } +/* Compacts the hash removing delete entries. */ +static void +sg_compact(mrb_state *mrb, seglist *t) +{ + segment *seg = t->rootseg; + mrb_int i; + segment *seg2 = NULL; + mrb_int i2; + mrb_int size = 0; + + while (seg) { + for (i=0; ie[i].key; + + if (!seg->next && i >= t->last_len) { + goto exit; + } + if (mrb_undef_p(k)) { /* found delete key */ + if (seg2 == NULL) { + seg2 = seg; + i2 = i; + } + } + else { + size++; + if (seg2 != NULL) { + seg2->e[i2++] = seg->e[i]; + if (i2 >= MRB_SG_SEGMENT_SIZE) { + seg2 = seg2->next; + i2 = 0; + } + } + } + } + seg = seg->next; + } + exit: + /* reached at end */ + t->size = size; + t->last_len = i2; + if (seg != seg2) { + seg = seg2->next; + seg2->next = NULL; + while (seg) { + seg2 = seg->next; + mrb_free(mrb, seg); + seg = seg2; + } + } +} + /* Deletes the value for the symbol from the instance variable table. */ +/* Deletion is done by overwriting keys by `undef`. */ static mrb_bool sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) { segment *seg; - size_t i; + mrb_int i; if (t == NULL) return FALSE; seg = t->rootseg; while (seg) { for (i=0; ikey[i]; + mrb_value k = seg->e[i].key; if (!seg->next && i >= t->last_len) { /* not found */ return FALSE; } + if (mrb_undef_p(k)) continue; if (mrb_hash_ht_hash_equal(mrb, k, key)) { - segment *sg0; - size_t i0; - - t->size--; - if (vp) *vp = seg->val[i]; - sg0 = seg; - i0 = i; - while (seg) { - for (i++; inext && i >= t->last_len) { - t->last_len--; - if (t->last_len == 0 && sg0 != seg) { - sg0->next = NULL; - t->last_len = MRB_SG_SEGMENT_SIZE; - mrb_free(mrb, seg); - } - return TRUE; - } - sg0->key[i0] = seg->key[i]; - sg0->val[i0] = seg->val[i]; - i0 = i; - } - sg0 = seg; - seg = seg->next; - } - t->last_len--; + if (vp) *vp = k; + seg->e[i].key = mrb_undef_value(); + if (t->size > 0) t->size = -1; + else t->size--; /* count number of deleted */ return TRUE; } } @@ -252,7 +287,7 @@ static void sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) { segment *seg; - size_t i; + mrb_int i; if (t == NULL) return; seg = t->rootseg; @@ -262,7 +297,8 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) if (!seg->next && i >= t->last_len) { return; } - if ((*func)(mrb, seg->key[i], seg->val[i], p) != 0) + if (mrb_undef_p(seg->e[i].key)) continue; + if ((*func)(mrb, seg->e[i].key, seg->e[i].val, p) != 0) return; } seg = seg->next; @@ -270,25 +306,14 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) } /* Get the size of the instance variable table. */ -static size_t +static mrb_int sg_size(mrb_state *mrb, seglist *t) { - segment *seg; - size_t size = 0; - if (t == NULL) return 0; - if (t->size > 0) return t->size; - seg = t->rootseg; - while (seg) { - if (seg->next == NULL) { - size += t->last_len; - return size; - } - seg = seg->next; - size += MRB_SG_SEGMENT_SIZE; + if (t->size < 0) { + sg_compact(mrb, t); } - /* empty seglist */ - return 0; + return t->size; } /* Copy the instance variable table. */ @@ -297,16 +322,15 @@ sg_copy(mrb_state *mrb, seglist *t) { segment *seg; seglist *t2; - - size_t i; + mrb_int i; seg = t->rootseg; t2 = sg_new(mrb); while (seg != NULL) { for (i=0; ikey[i]; - mrb_value val = seg->val[i]; + mrb_value key = seg->e[i].key; + mrb_value val = seg->e[i].val; if ((seg->next == NULL) && (i >= t->last_len)) { return t2; @@ -787,24 +811,6 @@ mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) return mrb_nil_value(); } -/* 15.2.13.4.8 */ -/* - * call-seq: - * hsh.delete(key) -> value - * hsh.delete(key) {| key | block } -> value - * - * Deletes and returns a key-value pair from hsh whose key is - * equal to key. If the key is not found, returns the - * default value. If the optional code block is given and the - * key is not found, pass in the key and return the result of - * block. - * - * h = { "a" => 100, "b" => 200 } - * h.delete("a") #=> 100 - * h.delete("z") #=> nil - * h.delete("z") { |el| "#{el} not found" } #=> "z not found" - * - */ static mrb_value mrb_hash_delete(mrb_state *mrb, mrb_value self) { @@ -836,8 +842,8 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_hash_modify(mrb, hash); if (sg && sg_size(mrb, sg) > 0) { - mrb_value del_key = sg->rootseg->key[0]; - mrb_value del_val = sg->rootseg->val[0]; + mrb_value del_key = sg->rootseg->e[0].key; + mrb_value del_val = sg->rootseg->e[0].val; sg_del(mrb, sg, del_key, NULL); return mrb_assoc_new(mrb, del_key, del_val); } -- cgit v1.2.3 From d78acc7afed35813f25e3091150dab668c373f05 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 26 Sep 2018 11:14:36 +0900 Subject: Add index to larger segment lists for performance --- mrbgems/mruby-array-ext/mrblib/array.rb | 14 +- mrblib/hash.rb | 2 +- src/hash.c | 440 +++++++++++++++++++++++--------- 3 files changed, 329 insertions(+), 127 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 8c2acc7ac..eac8d4718 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -1,3 +1,4 @@ +# coding: cp932 class Array ## # call-seq: @@ -41,26 +42,19 @@ class Array # c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] # def uniq!(&block) + hash = {} if block - hash = {} self.each do |val| key = block.call(val) hash[key] = val unless hash.key?(key) end result = hash.values - elsif self.size > 20 + else hash = {} self.each do |val| hash[val] = val end - result = hash.values - else - ary = self.dup - result = [] - while ary.size > 0 - result << ary.shift - ary.delete(result.last) - end + result = hash.keys end if result.size == self.size nil diff --git a/mrblib/hash.rb b/mrblib/hash.rb index eba92ba4a..245b76ee0 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -334,7 +334,7 @@ class Hash # h["AA"] #=> "b" # def rehash - self.size + # do nothing (for now) self end end diff --git a/src/hash.c b/src/hash.c index 820ee5a71..07a12be68 100644 --- a/src/hash.c +++ b/src/hash.c @@ -16,14 +16,48 @@ mrb_int mrb_float_id(mrb_float f); #endif -static inline khint_t -mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) +/* return non zero to break the loop */ +typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); + +#ifndef MRB_SG_SEGMENT_SIZE +#define MRB_SG_SEGMENT_SIZE 5 +#endif + +struct segkv { + mrb_value key; + mrb_value val; +}; + +typedef struct segment { + struct segment *next; + struct segkv e[MRB_SG_SEGMENT_SIZE]; +} segment; + +typedef struct segindex { + size_t size; + size_t capa; + struct segkv *table[]; +} segindex; + +/* Instance variable table structure */ +typedef struct seglist { + segment *rootseg; + segment *lastseg; + mrb_int size; + mrb_int last_len; + segindex *index; +} seglist; + +static /* inline */ size_t +sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key) { - enum mrb_vtype t = mrb_type(key); + enum mrb_vtype tt = mrb_type(key); mrb_value hv; - khint_t h; + size_t h; + segindex *index = t->index; + size_t capa = index ? index->capa : 0; - switch (t) { + switch (tt) { case MRB_TT_STRING: h = mrb_str_hash(mrb, key); break; @@ -35,23 +69,26 @@ mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: #endif - h = (khint_t)mrb_obj_id(key); + h = (size_t)mrb_obj_id(key); break; default: hv = mrb_funcall(mrb, key, "hash", 0); - h = (khint_t)t ^ (khint_t)mrb_fixnum(hv); + h = (size_t)t ^ (size_t)mrb_fixnum(hv); break; } - return kh_int_hash_func(mrb, h); + if (index && (index != t->index || capa != index->capa)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); + } + return ((h)^((h)<<2)^((h)>>2)); } static inline mrb_bool -mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) +sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b) { - enum mrb_vtype t = mrb_type(a); + enum mrb_vtype tt = mrb_type(a); - switch (t) { + switch (tt) { case MRB_TT_STRING: return mrb_str_equal(mrb, a, b); @@ -84,32 +121,18 @@ mrb_hash_ht_hash_equal(mrb_state *mrb, mrb_value a, mrb_value b) #endif default: - return mrb_eql(mrb, a, b); - } + { + segindex *index = t->index; + size_t capa = index ? index->capa : 0; + mrb_bool eql = mrb_eql(mrb, a, b); + if (index && (index != t->index || capa != index->capa)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified"); + } + return eql; + } + } } -/* return non zero to break the loop */ -typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key,mrb_value val, void *data); - -#ifndef MRB_SG_SEGMENT_SIZE -#define MRB_SG_SEGMENT_SIZE 5 -#endif - -typedef struct segment { - struct segment *next; - struct { - mrb_value key; - mrb_value val; - } e[MRB_SG_SEGMENT_SIZE]; -} segment; - -/* Instance variable table structure */ -typedef struct seglist { - segment *rootseg; - mrb_int size; - mrb_int last_len; -} seglist; - /* Creates the instance variable table. */ static seglist* sg_new(mrb_state *mrb) @@ -119,87 +142,87 @@ sg_new(mrb_state *mrb) t = (seglist*)mrb_malloc(mrb, sizeof(seglist)); t->size = 0; t->rootseg = NULL; + t->lastseg = NULL; t->last_len = 0; + t->index = NULL; return t; } -/* Set the value for the symbol in the instance variable table. */ +#define power2(v) do { \ + v--;\ + v |= v >> 1;\ + v |= v >> 2;\ + v |= v >> 4;\ + v |= v >> 8;\ + v |= v >> 16;\ + v++;\ +} while (0) + +#ifndef UPPER_BOUND +#define UPPER_BOUND(x) ((x)>>2|(x)>>1) +#endif + +#define SG_MASK(index) ((index->capa)-1) + +/* Build index for the segment list */ static void -sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +sg_index(mrb_state *mrb, seglist *t) { + size_t size = (size_t)t->size; + size_t mask; + segindex *index = t->index; segment *seg; - segment *prev = NULL; - mrb_int i; + size_t i; - if (t == NULL) return; - seg = t->rootseg; - while (seg) { - for (i=0; ie[i].key; - /* Found room in last segment after last_len */ - if (!seg->next && i >= t->last_len) { - seg->e[i].key = key; - seg->e[i].val = val; - t->last_len = i+1; - if (t->size >= 0) t->size++; - return; - } - if (mrb_undef_p(k)) continue; - if (mrb_hash_ht_hash_equal(mrb, k, key)) { - seg->e[i].val = val; - return; - } + if (size < MRB_SG_SEGMENT_SIZE) { + if (index) { + failed: + mrb_free(mrb, index); + t->index = NULL; } - prev = seg; - seg = seg->next; + return; } - - /* Not found */ - if (t->size >= 0) t->size++; - - seg = (segment*)mrb_malloc(mrb, sizeof(segment)); - if (!seg) return; - seg->next = NULL; - seg->e[0].key = key; - seg->e[0].val = val; - t->last_len = 1; - if (prev) { - prev->next = seg; + /* allocate index table */ + if (index && index->size >= UPPER_BOUND(index->capa)) { + size = index->capa+1; } - else { - t->rootseg = seg; + power2(size); + if (!index || index->capa < size) { + index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); + if (index == NULL) goto failed; + t->index = index; + } + index->size = t->size; + index->capa = size; + for (i=0; itable[i] = NULL; } -} - -/* Get a value for a symbol from the instance variable table. */ -static mrb_bool -sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) -{ - segment *seg; - mrb_int i; - if (t == NULL) return FALSE; + /* rebuld index */ + mask = SG_MASK(index); seg = t->rootseg; while (seg) { for (i=0; ie[i].key; + mrb_value key; + size_t k, step = 0; - if (!seg->next && i >= t->last_len) { - return FALSE; + if (!seg->next && i >= (size_t)t->last_len) { + return; } - if (mrb_undef_p(k)) continue; - if (mrb_hash_ht_hash_equal(mrb, k, key)) { - if (vp) *vp = seg->e[i].val; - return TRUE; + key = seg->e[i].key; + if (mrb_undef_p(key)) continue; + k = sg_hash_func(mrb, t, key) & mask; + while (index->table[k]) { + k = (k+(++step)) & mask; } + index->table[k] = &seg->e[i]; } seg = seg->next; } - return FALSE; } -/* Compacts the hash removing delete entries. */ +/* Compacts the segment list removing deleted entries. */ static void sg_compact(mrb_state *mrb, seglist *t) { @@ -209,6 +232,10 @@ sg_compact(mrb_state *mrb, seglist *t) mrb_int i2; mrb_int size = 0; + if (t->index && (size_t)t->size == t->index->size) { + sg_index(mrb, t); + return; + } while (seg) { for (i=0; ie[i].key; @@ -238,16 +265,179 @@ sg_compact(mrb_state *mrb, seglist *t) exit: /* reached at end */ t->size = size; - t->last_len = i2; - if (seg != seg2) { + if (seg2) { seg = seg2->next; seg2->next = NULL; + t->last_len = i2; + t->lastseg = seg2; while (seg) { seg2 = seg->next; mrb_free(mrb, seg); seg = seg2; } } + if (t->index) { + sg_index(mrb, t); + } +} + +/* Set the value for the key in the indexed segment list. */ +static void +sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +{ + segindex *index = t->index; + size_t k, sp, step = 0, mask; + segment *seg; + + if (index->size >= UPPER_BOUND(index->capa)) { + /* need to expand table */ + sg_compact(mrb, t); + index = t->index; + } + mask = SG_MASK(index); + sp = index->capa; + k = sg_hash_func(mrb, t, key) & mask; + while (index->table[k]) { + mrb_value key2 = index->table[k]->key; + if (mrb_undef_p(key2)) { + if (sp == index->capa) sp = k; + } + else if (sg_hash_equal(mrb, t, key, key2)) { + index->table[k]->val = val; + return; + } + k = (k+(++step)) & mask; + } + if (sp < index->capa) { + k = sp; + } + + /* put the value at the last */ + seg = t->lastseg; + if (t->last_len < MRB_SG_SEGMENT_SIZE) { + index->table[k] = &seg->e[t->last_len++]; + } + else { /* append a new segment */ + seg->next = (segment*)mrb_malloc(mrb, sizeof(segment)); + seg = seg->next; + seg->next = NULL; + t->lastseg = seg; + t->last_len = 1; + index->table[k] = &seg->e[0]; + } + index->table[k]->key = key; + index->table[k]->val = val; + index->size++; + t->size++; +} + +/* Set the value for the key in the segment list. */ +static void +sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +{ + segment *seg; + mrb_int i, deleted = 0; + + if (t == NULL) return; + if (t->index) { + sg_index_put(mrb, t, key, val); + return; + } + seg = t->rootseg; + while (seg) { + for (i=0; ie[i].key; + /* Found room in last segment after last_len */ + if (!seg->next && i >= t->last_len) { + seg->e[i].key = key; + seg->e[i].val = val; + t->last_len = i+1; + t->size++; + return; + } + if (mrb_undef_p(k)) { + deleted++; + continue; + } + if (sg_hash_equal(mrb, t, k, key)) { + seg->e[i].val = val; + return; + } + } + seg = seg->next; + } + + /* Not found */ + if (deleted > MRB_SG_SEGMENT_SIZE) { + sg_compact(mrb, t); + } + t->size++; + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); + seg->next = NULL; + seg->e[0].key = key; + seg->e[0].val = val; + t->last_len = 1; + if (t->rootseg == NULL) { + t->rootseg = seg; + } + else { + t->lastseg->next = seg; + } + t->lastseg = seg; + if (t->index == NULL && t->size > MRB_SG_SEGMENT_SIZE*4) { + sg_index(mrb, t); + } +} + +/* Get a value for a key from the indexed segment list. */ +static mrb_bool +sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +{ + segindex *index = t->index; + size_t mask = SG_MASK(index); + size_t k = sg_hash_func(mrb, t, key) & mask; + size_t step = 0; + + while (index->table[k]) { + if (sg_hash_equal(mrb, t, key, index->table[k]->key)) { + if (vp) *vp = index->table[k]->val; + return TRUE; + } + k = (k+(++step)) & mask; + } + return FALSE; +} + +/* Get a value for a key from the segment list. */ +static mrb_bool +sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +{ + segment *seg; + mrb_int i; + + if (t == NULL) return FALSE; + if (t->index) { + return sg_index_get(mrb, t, key, vp); + } + + seg = t->rootseg; + while (seg) { + for (i=0; ie[i].key; + + if (!seg->next && i >= t->last_len) { + return FALSE; + } + if (mrb_undef_p(k)) continue; + if (sg_hash_equal(mrb, t, k, key)) { + if (vp) *vp = seg->e[i].val; + return TRUE; + } + } + seg = seg->next; + } + return FALSE; } /* Deletes the value for the symbol from the instance variable table. */ @@ -262,18 +452,17 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) seg = t->rootseg; while (seg) { for (i=0; ie[i].key; + mrb_value key2; if (!seg->next && i >= t->last_len) { /* not found */ return FALSE; } - if (mrb_undef_p(k)) continue; - if (mrb_hash_ht_hash_equal(mrb, k, key)) { - if (vp) *vp = k; + key2 = seg->e[i].key; + if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { + if (vp) *vp = key2; seg->e[i].key = mrb_undef_value(); - if (t->size > 0) t->size = -1; - else t->size--; /* count number of deleted */ + t->size--; return TRUE; } } @@ -290,6 +479,9 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) mrb_int i; if (t == NULL) return; + if (t->index && t->index->size-(size_t)t->size > MRB_SG_SEGMENT_SIZE) { + sg_compact(mrb, t); + } seg = t->rootseg; while (seg) { for (i=0; isize < 0) { - sg_compact(mrb, t); - } return t->size; } @@ -355,13 +544,14 @@ sg_free(mrb_state *mrb, seglist *t) seg = seg->next; mrb_free(mrb, p); } + if (t->index) mrb_free(mrb, t->index); mrb_free(mrb, t); } static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value -mrb_hash_ht_key(mrb_state *mrb, mrb_value key) +ht_key(mrb_state *mrb, mrb_value key) { if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); @@ -370,7 +560,7 @@ mrb_hash_ht_key(mrb_state *mrb, mrb_value key) return key; } -#define KEY(key) mrb_hash_ht_key(mrb, key) +#define KEY(key) ht_key(mrb, key) static int hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) @@ -489,15 +679,6 @@ mrb_hash_dup(mrb_state *mrb, mrb_value self) return mrb_obj_value(copy); } -MRB_API mrb_bool -mrb_hash_has_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) -{ - if (sg_get(mrb, RHASH_TBL(hash), key, NULL)) { - return TRUE; - } - return FALSE; -} - MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { @@ -821,6 +1002,33 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } +/* find first element in segment list, and remove it. */ +static void +sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp) +{ + segment *seg = t->rootseg; + mrb_int i; + + while (seg) { + for (i=0; inext && i >= t->last_len) { + return; + } + key = seg->e[i].key; + if (mrb_undef_p(key)) continue; + *kp = key; + *vp = seg->e[i].val; + /* delete element */ + seg->e[i].key = mrb_undef_value(); + t->size--; + return; + } + seg = seg->next; + } +} + /* 15.2.13.4.24 */ /* * call-seq: @@ -842,9 +1050,9 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_hash_modify(mrb, hash); if (sg && sg_size(mrb, sg) > 0) { - mrb_value del_key = sg->rootseg->e[0].key; - mrb_value del_val = sg->rootseg->e[0].val; - sg_del(mrb, sg, del_key, NULL); + mrb_value del_key, del_val; + + sg_shift(mrb, sg, &del_key, &del_val); return mrb_assoc_new(mrb, del_key, del_val); } -- cgit v1.2.3 From 54ec08c7f19e7c46de3dcb63e4f30cd65e4a56e7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 26 Sep 2018 13:04:13 +0900 Subject: Implement `Hash#rehash` in C using `sg_compact()`. --- mrblib/hash.rb | 20 -------------------- src/hash.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 245b76ee0..582cfbc6c 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -317,26 +317,6 @@ class Hash } h end - - ## - # call-seq: - # hsh.rehash -> hsh - # - # Rebuilds the hash based on the current hash values for each key. If - # values of key objects have changed since they were inserted, this - # method will reindex hsh. - # - # h = {"AAA" => "b"} - # h.keys[0].chop! - # h #=> {"AA"=>"b"} - # h["AA"] #=> nil - # h.rehash #=> {"AA"=>"b"} - # h["AA"] #=> "b" - # - def rehash - # do nothing (for now) - self - end end ## diff --git a/src/hash.c b/src/hash.c index 07a12be68..21dc846af 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1367,6 +1367,26 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) return; } +/* + * call-seq: + * hsh.rehash -> hsh + * + * Rebuilds the hash based on the current hash values for each key. If + * values of key objects have changed since they were inserted, this + * method will reindex hsh. + * + * h = {"AAA" => "b"} + * h.keys[0].chop! + * h.rehash #=> {"AA"=>"b"} + * h["AA"] #=> "b" + */ +static mrb_value +mrb_hash_rehash(mrb_state *mrb, mrb_value self) +{ + sg_compact(mrb, RHASH_TBL(self)); + return self; +} + void mrb_init_hash(mrb_state *mrb) { @@ -1398,6 +1418,7 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "store", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.26 */ mrb_define_method(mrb, h, "value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.27 */ mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */ + mrb_define_method(mrb, h, "rehash", mrb_hash_rehash, MRB_ARGS_NONE()); mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/ } -- cgit v1.2.3 From 82e00ce60f358489ae2c3a7fdbe4da9bf264b286 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Oct 2018 08:25:54 +0900 Subject: `Hash#delete` should return the deleted value; fix #4133 --- src/hash.c | 2 +- test/t/hash.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 21dc846af..5bccb3091 100644 --- a/src/hash.c +++ b/src/hash.c @@ -460,7 +460,7 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) } key2 = seg->e[i].key; if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { - if (vp) *vp = key2; + if (vp) *vp = seg->e[i].val; seg->e[i].key = mrb_undef_value(); t->size--; return TRUE; diff --git a/test/t/hash.rb b/test/t/hash.rb index 5403a5901..8088bfa21 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -82,12 +82,12 @@ assert('Hash#default_proc', '15.2.13.4.7') do end assert('Hash#delete', '15.2.13.4.8') do - a = { 'abc' => 'abc' } - b = { 'abc' => 'abc' } + a = { 'abc' => 'ABC' } + b = { 'abc' => 'ABC' } b_tmp_1 = false b_tmp_2 = false - a.delete('abc') + assert_equal 'ABC', a.delete('abc') b.delete('abc') do |k| b_tmp_1 = true end -- cgit v1.2.3 From 249fef7dc49ee5c22256aa7e9c36cd788e0ba323 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Oct 2018 08:30:57 +0900 Subject: Add `NULL` check in `sg_compact()`; fix #4139 --- src/hash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 5bccb3091..325c7e66f 100644 --- a/src/hash.c +++ b/src/hash.c @@ -226,12 +226,14 @@ sg_index(mrb_state *mrb, seglist *t) static void sg_compact(mrb_state *mrb, seglist *t) { - segment *seg = t->rootseg; + segment *seg; mrb_int i; segment *seg2 = NULL; mrb_int i2; mrb_int size = 0; + if (t == NULL) return; + seg = t->rootseg; if (t->index && (size_t)t->size == t->index->size) { sg_index(mrb, t); return; -- cgit v1.2.3 From e5f160dc7ec4f5ae596a7129f368ccc06186c3ee Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Oct 2018 19:00:45 +0900 Subject: Should not compare `undef` (deleted) key in hashes; fix #4136 --- src/hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 325c7e66f..e1ceec489 100644 --- a/src/hash.c +++ b/src/hash.c @@ -402,7 +402,8 @@ sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) size_t step = 0; while (index->table[k]) { - if (sg_hash_equal(mrb, t, key, index->table[k]->key)) { + mrb_value key2 = index->table[k]->key; + if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { if (vp) *vp = index->table[k]->val; return TRUE; } -- cgit v1.2.3 From 80b5a56f5139c9bcc6f064ac77c7a69b7489137c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 20 Oct 2018 19:02:12 +0900 Subject: Need to freeze string keys. --- src/hash.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index e1ceec489..03a95dbd8 100644 --- a/src/hash.c +++ b/src/hash.c @@ -717,6 +717,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) { mrb_hash_modify(mrb, hash); + key = KEY(key); sg_put(mrb, RHASH_TBL(hash), key, val); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val); -- cgit v1.2.3 From 7ff84789c3f77f0d61441f9afb22a1039ea7cc4a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 10:12:10 +0900 Subject: Add argument check to `Array#clear`; fix #4144 --- src/array.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/array.c b/src/array.c index 0b039a6ec..eddd9b2ac 100644 --- a/src/array.c +++ b/src/array.c @@ -1100,6 +1100,7 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); + mrb_get_args(mrb, ""); ary_modify(mrb, a); if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->as.heap.aux.shared); -- cgit v1.2.3 From dffa203d07aaeec4ea65669542a8ec2033559bdd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 11:51:04 +0900 Subject: Need to mark shared env objects as `MRB_TT_FREE`; fix #4143 The following code mistakenly exits from the function without marking the env object as `MRB_TT_FREE`. ``` ruby if (MRB_ENV_STACK_SHARED_P(e)) { /* cannot be freed */ return; // <- should be `break` } ``` --- src/gc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index e429603dd..9b11b7a83 100644 --- a/src/gc.c +++ b/src/gc.c @@ -788,7 +788,8 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) if (MRB_ENV_STACK_SHARED_P(e)) { /* cannot be freed */ - return; + e->stack = NULL; + break; } mrb_free(mrb, e->stack); e->stack = NULL; -- cgit v1.2.3 From 3dc3643e34e1e9f119594ebd550f19e876d60e26 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 11:58:10 +0900 Subject: Marking from terminated fibers are not needed; ref #4143 The old condition marks the top-level callinfo even after the fiber is terminated. --- src/gc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 9b11b7a83..bacc322e8 100644 --- a/src/gc.c +++ b/src/gc.c @@ -801,10 +801,10 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) struct mrb_context *c = ((struct RFiber*)obj)->cxt; if (c && c != mrb->root_c) { - mrb_callinfo *ci = c->ci; - mrb_callinfo *ce = c->cibase; + if (!end && c->status != MRB_FIBER_TERMINATED) { + mrb_callinfo *ci = c->ci; + mrb_callinfo *ce = c->cibase; - if (!end) { while (ce <= ci) { struct REnv *e = ci->env; if (e && !is_dead(&mrb->gc, e) && -- cgit v1.2.3 From fa33a4d75a33c303a78b5bbd7743e207e3e89d61 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Oct 2018 12:01:27 +0900 Subject: We need no write barrier here; ref #4143 --- src/vm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 9eeb388fc..067dd90f7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1984,10 +1984,7 @@ RETRY_TRY_BLOCK: while (c->eidx > ci->epos) { ecall_adjust(); } - if (c->fib) { - mrb_write_barrier(mrb, (struct RBasic*)c->fib); - } - mrb->c->status = MRB_FIBER_TERMINATED; + c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; goto L_RAISE; -- cgit v1.2.3 From b37b31208152fdee0cb99e00cffec0b9e57040c6 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 13:56:20 +0900 Subject: Rename libmruby stuff to avoid confusion --- Rakefile | 4 ++-- lib/mruby/build.rb | 18 ++++++++++++++++-- lib/mruby/gem.rb | 2 +- mrbgems/mruby-bin-mrbc/mrbgem.rake | 2 +- mrbgems/mruby-bin-mruby-config/mrbgem.rake | 2 +- mrbgems/mruby-compiler/mrbgem.rake | 2 +- mrbgems/mruby-test/mrbgem.rake | 5 +---- mrblib/mrblib.rake | 2 +- src/mruby_core.rake | 4 ++-- tasks/libmruby.rake | 6 +++--- tasks/mrbgems.rake | 2 +- 11 files changed, 30 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/Rakefile b/Rakefile index d2ad9044c..20b6096f5 100644 --- a/Rakefile +++ b/Rakefile @@ -65,7 +65,7 @@ MRuby.each_target do |target| exec = exefile("#{build_dir}/bin/#{bin}") objs = Dir.glob("#{current_dir}/tools/#{bin}/*.{c,cpp,cxx,cc}").map { |f| objfile(f.pathmap("#{current_build_dir}/tools/#{bin}/%n")) } - file exec => objs + [libfile("#{build_dir}/lib/libmruby")] do |t| + file exec => objs + target.libraries do |t| gem_flags = gems.map { |g| g.linker.flags } gem_flags_before_libraries = gems.map { |g| g.linker.flags_before_libraries } gem_flags_after_libraries = gems.map { |g| g.linker.flags_after_libraries } @@ -100,7 +100,7 @@ MRuby.each_target do |target| end depfiles += MRuby.targets.map { |n, t| - [t.libfile("#{t.build_dir}/lib/libmruby")] + t.libraries }.flatten depfiles += MRuby.targets.reject { |n, t| n == 'host' }.map { |n, t| diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index 047ae13dc..7a0f7a759 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -45,9 +45,11 @@ module MRuby include Rake::DSL include LoadGems attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir - attr_reader :libmruby, :gems, :toolchains + attr_reader :libmruby_objs, :gems, :toolchains attr_writer :enable_bintest, :enable_test + alias libmruby libmruby_objs + COMPILERS = %w(cc cxx objc asm) COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc) attr_block MRuby::Build::COMMANDS @@ -81,7 +83,7 @@ module MRuby @mrbc = Command::Mrbc.new(self) @bins = [] - @gems, @libmruby = MRuby::Gem::List.new, [] + @gems, @libmruby_objs = MRuby::Gem::List.new, [] @build_mrbtest_lib_only = false @cxx_exception_enabled = false @cxx_exception_disabled = false @@ -327,6 +329,18 @@ EOS puts "================================================" puts end + + def libmruby_static + libfile("#{build_dir}/lib/libmruby") + end + + def libmruby_core_static + libfile("#{build_dir}/lib/libmruby_core") + end + + def libraries + [libmruby_static] + end end # Build class CrossBuild < Build diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 7e97c34f3..ba4d5d17a 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -87,7 +87,7 @@ module MRuby fail "#{name || dir} required to set name, license(s) and author(s)" end - build.libmruby << @objs + build.libmruby_objs << @objs instance_eval(&@build_config_initializer) if @build_config_initializer end diff --git a/mrbgems/mruby-bin-mrbc/mrbgem.rake b/mrbgems/mruby-bin-mrbc/mrbgem.rake index e710b5a49..48b67aedb 100644 --- a/mrbgems/mruby-bin-mrbc/mrbgem.rake +++ b/mrbgems/mruby-bin-mrbc/mrbgem.rake @@ -8,7 +8,7 @@ MRuby::Gem::Specification.new 'mruby-bin-mrbc' do |spec| exec = exefile("#{build.build_dir}/bin/mrbc") mrbc_objs = Dir.glob("#{spec.dir}/tools/mrbc/*.c").map { |f| objfile(f.pathmap("#{spec.build_dir}/tools/mrbc/%n")) }.flatten - file exec => mrbc_objs + [libfile("#{build.build_dir}/lib/libmruby_core")] do |t| + file exec => mrbc_objs + [build.libmruby_core_static] do |t| build.linker.run t.name, t.prerequisites end diff --git a/mrbgems/mruby-bin-mruby-config/mrbgem.rake b/mrbgems/mruby-bin-mruby-config/mrbgem.rake index 32ae2164b..cca7423ac 100644 --- a/mrbgems/mruby-bin-mruby-config/mrbgem.rake +++ b/mrbgems/mruby-bin-mruby-config/mrbgem.rake @@ -20,7 +20,7 @@ MRuby.each_target do @bins << mruby_config make_cfg = "#{build_dir}/lib/libmruby.flags.mak" - file mruby_config_path => [libfile("#{build_dir}/lib/libmruby"), make_cfg] do |t| + file mruby_config_path => [libmruby_static, make_cfg] do |t| FileUtils.copy "#{File.dirname(__FILE__)}/#{mruby_config}", t.name config = Hash[open(make_cfg).read.split("\n").map {|x| a = x.split(/\s*=\s*/, 2); [a[0], a[1].gsub('\\"', '"') ]}] IO.write(t.name, File.open(t.name) {|f| diff --git a/mrbgems/mruby-compiler/mrbgem.rake b/mrbgems/mruby-compiler/mrbgem.rake index e9e0cc2c7..fa191e69b 100644 --- a/mrbgems/mruby-compiler/mrbgem.rake +++ b/mrbgems/mruby-compiler/mrbgem.rake @@ -35,6 +35,6 @@ MRuby::Gem::Specification.new 'mruby-compiler' do |spec| gperf.run t.name, t.prerequisites.first end - file libfile("#{build.build_dir}/lib/libmruby_core") => core_objs + file build.libmruby_core_static => core_objs build.libmruby << core_objs end diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 589fc688a..c9d254bfe 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -16,9 +16,6 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| mlib = clib.ext(exts.object) exec = exefile("#{build.build_dir}/bin/mrbtest") - libmruby = libfile("#{build.build_dir}/lib/libmruby") - libmruby_core = libfile("#{build.build_dir}/lib/libmruby_core") - mrbtest_lib = libfile("#{build_dir}/mrbtest") mrbtest_objs = [] @@ -140,7 +137,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| end unless build.build_mrbtest_lib_only? - file exec => [driver_obj, mlib, mrbtest_lib, libmruby_core, libmruby] do |t| + file exec => [driver_obj, mlib, mrbtest_lib, build.libmruby_static] do |t| gem_flags = build.gems.map { |g| g.linker.flags } gem_flags_before_libraries = build.gems.map { |g| g.linker.flags_before_libraries } gem_flags_after_libraries = build.gems.map { |g| g.linker.flags_after_libraries } diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake index fe4aae1f7..6895d4252 100644 --- a/mrblib/mrblib.rake +++ b/mrblib/mrblib.rake @@ -3,7 +3,7 @@ MRuby.each_target do relative_from_root = File.dirname(__FILE__).relative_path_from(MRUBY_ROOT) current_build_dir = "#{build_dir}/#{relative_from_root}" - self.libmruby << objfile("#{current_build_dir}/mrblib") + self.libmruby_objs << objfile("#{current_build_dir}/mrblib") file objfile("#{current_build_dir}/mrblib") => "#{current_build_dir}/mrblib.c" file "#{current_build_dir}/mrblib.c" => [mrbcfile, __FILE__] + Dir.glob("#{current_dir}/*.rb").sort do |t| diff --git a/src/mruby_core.rake b/src/mruby_core.rake index bb3d7b633..3024c8544 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -12,9 +12,9 @@ MRuby.each_target do if cxx_exception_enabled? objs += %w(vm error).map { |v| compile_as_cxx "#{current_dir}/#{v}.c", "#{current_build_dir}/#{v}.cxx" } end - self.libmruby << objs + self.libmruby_objs << objs - file libfile("#{build_dir}/lib/libmruby_core") => objs do |t| + file libmruby_core_static => objs do |t| archiver.run t.name, t.prerequisites end end diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake index b6ef29986..ab5a15b4a 100644 --- a/tasks/libmruby.rake +++ b/tasks/libmruby.rake @@ -1,9 +1,9 @@ MRuby.each_target do - file libfile("#{build_dir}/lib/libmruby") => libmruby.flatten do |t| + file libmruby_static => libmruby_objs.flatten do |t| archiver.run t.name, t.prerequisites end - file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libfile("#{build_dir}/lib/libmruby")] do |t| + file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libmruby_static] do |t| FileUtils.mkdir_p File.dirname t.name open(t.name, 'w') do |f| f.puts "MRUBY_CFLAGS = #{cc.all_flags}" @@ -18,7 +18,7 @@ MRuby.each_target do gem_libraries = gems.map { |g| g.linker.libraries } f.puts "MRUBY_LIBS = #{linker.option_library % 'mruby'} #{linker.library_flags(gem_libraries)}" - f.puts "MRUBY_LIBMRUBY_PATH = #{libfile("#{build_dir}/lib/libmruby")}" + f.puts "MRUBY_LIBMRUBY_PATH = #{libmruby_static}" end end task :all => "#{build_dir}/lib/libmruby.flags.mak" diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index e2aeb1514..fb76856e5 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -5,7 +5,7 @@ MRuby.each_target do gems.check self # loader all gems - self.libmruby << objfile("#{build_dir}/mrbgems/gem_init") + self.libmruby_objs << objfile("#{build_dir}/mrbgems/gem_init") file objfile("#{build_dir}/mrbgems/gem_init") => ["#{build_dir}/mrbgems/gem_init.c", "#{build_dir}/LEGAL"] file "#{build_dir}/mrbgems/gem_init.c" => [MRUBY_CONFIG, __FILE__] do |t| FileUtils.mkdir_p "#{build_dir}/mrbgems" -- cgit v1.2.3 From 3248de83b6754eecc99d9ab6fdef8bb3575fcd04 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:17:05 +0900 Subject: Reduce instruction size --- include/mruby/ops.h | 22 ++++++------- include/mruby/symbol.h | 32 ++++++++++++++++++ mrbgems/mruby-compiler/core/codegen.c | 43 ++++++++++++------------ src/symbol.c | 26 +++++++++++++++ src/vm.c | 62 ++++++++++++++++++++++------------- 5 files changed, 130 insertions(+), 55 deletions(-) create mode 100644 include/mruby/symbol.h (limited to 'src') diff --git a/include/mruby/ops.h b/include/mruby/ops.h index f23bb1b0b..7531a5ee2 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -70,17 +70,17 @@ OPCODE(RETURN, B) /* return R(a) (normal) */ OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ OPCODE(BREAK, B) /* break R(a) */ OPCODE(BLKPUSH, BS) /* R(a) = block (16=m5:r1:m5:d1:lv4) */ -OPCODE(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */ -OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (Syms[b]=:+) */ -OPCODE(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */ -OPCODE(SUBI, BBB) /* R(a) = R(a)-C (Syms[b]=:-) */ -OPCODE(MUL, BB) /* R(a) = R(a)*R(a+1) (Syms[b]=:*) */ -OPCODE(DIV, BB) /* R(a) = R(a)/R(a+1) (Syms[b]=:/) */ -OPCODE(EQ, BB) /* R(a) = R(a)==R(a+1) (Syms[b]=:==) */ -OPCODE(LT, BB) /* R(a) = R(a)R(a+1) (Syms[b]=:>) */ -OPCODE(GE, BB) /* R(a) = R(a)>=R(a+1) (Syms[b]=:>=) */ +OPCODE(ADD, B) /* R(a) = R(a)+R(a+1) */ +OPCODE(ADDI, BB) /* R(a) = R(a)+mrb_int(c) */ +OPCODE(SUB, B) /* R(a) = R(a)-R(a+1) */ +OPCODE(SUBI, BB) /* R(a) = R(a)-C */ +OPCODE(MUL, B) /* R(a) = R(a)*R(a+1) */ +OPCODE(DIV, B) /* R(a) = R(a)/R(a+1) */ +OPCODE(EQ, B) /* R(a) = R(a)==R(a+1) */ +OPCODE(LT, B) /* R(a) = R(a)R(a+1) */ +OPCODE(GE, B) /* R(a) = R(a)>=R(a+1) */ OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */ OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */ OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */ diff --git a/include/mruby/symbol.h b/include/mruby/symbol.h new file mode 100644 index 000000000..595caeefd --- /dev/null +++ b/include/mruby/symbol.h @@ -0,0 +1,32 @@ +/* +** mruby/symbol.h - symbol utilities +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_SYMBOL_H +#define MRUBY_SYMBOL_H + +#include "common.h" + +/** + * Symbol utilities + */ +MRB_BEGIN_DECL + +typedef enum mrb_reserved_symbol { + mrb_sym_add = 1, // + + mrb_sym_sub = 2, // - + mrb_sym_mul = 3, // * + mrb_sym_div = 4, // / + mrb_sym_eq = 5, // == + mrb_sym_lt = 6, // < + mrb_sym_le = 7, // <= + mrb_sym_gt = 8, // > + mrb_sym_ge = 9, // >= + mrb_sym_method_missing = 10, // method_missing +} mrb_reserved_symbol; + +MRB_END_DECL + +#endif /* MRUBY_SYMBOL_H */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 8ab1b9bc3..759e7267e 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -468,11 +468,11 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src) } static void -gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) +gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) { if (no_peephole(s)) { normal: - genop_2(s, op, dst, idx); + genop_1(s, op, dst); return; } else { @@ -493,10 +493,10 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) if (data.b >= 128) goto normal; s->pc = s->lastpc; if (op == OP_ADD) { - genop_3(s, OP_ADDI, dst, idx, (uint8_t)data.b); + genop_2(s, OP_ADDI, dst, (uint8_t)data.b); } else { - genop_3(s, OP_SUBI, dst, idx, (uint8_t)data.b); + genop_2(s, OP_SUBI, dst, (uint8_t)data.b); } break; default: @@ -982,6 +982,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) gen_move(s, cursp(), recv, 1); skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } + // TODO: don't new when unused idx = new_sym(s, sym); tree = tree->cdr->cdr->car; if (tree) { @@ -1017,31 +1018,31 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen); if (!noop && symlen == 1 && symname[0] == '+' && n == 1) { - gen_addsub(s, OP_ADD, cursp(), idx); + gen_addsub(s, OP_ADD, cursp()); } else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) { - gen_addsub(s, OP_SUB, cursp(), idx); + gen_addsub(s, OP_SUB, cursp()); } else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) { - genop_2(s, OP_MUL, cursp(), idx); + genop_1(s, OP_MUL, cursp()); } else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) { - genop_2(s, OP_DIV, cursp(), idx); + genop_1(s, OP_DIV, cursp()); } else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) { - genop_2(s, OP_LT, cursp(), idx); + genop_1(s, OP_LT, cursp()); } else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) { - genop_2(s, OP_LE, cursp(), idx); + genop_1(s, OP_LE, cursp()); } else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) { - genop_2(s, OP_GT, cursp(), idx); + genop_1(s, OP_GT, cursp()); } else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) { - genop_2(s, OP_GE, cursp(), idx); + genop_1(s, OP_GE, cursp()); } else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) { - genop_2(s, OP_EQ, cursp(), idx); + genop_1(s, OP_EQ, cursp()); } else { if (sendv) { @@ -2025,28 +2026,28 @@ codegen(codegen_scope *s, node *tree, int val) idx = new_sym(s, sym); if (len == 1 && name[0] == '+') { - gen_addsub(s, OP_ADD, cursp(), idx); + gen_addsub(s, OP_ADD, cursp()); } else if (len == 1 && name[0] == '-') { - gen_addsub(s, OP_SUB, cursp(), idx); + gen_addsub(s, OP_SUB, cursp()); } else if (len == 1 && name[0] == '*') { - genop_2(s, OP_MUL, cursp(), idx); + genop_1(s, OP_MUL, cursp()); } else if (len == 1 && name[0] == '/') { - genop_2(s, OP_DIV, cursp(), idx); + genop_1(s, OP_DIV, cursp()); } else if (len == 1 && name[0] == '<') { - genop_2(s, OP_LT, cursp(), idx); + genop_1(s, OP_LT, cursp()); } else if (len == 2 && name[0] == '<' && name[1] == '=') { - genop_2(s, OP_LE, cursp(), idx); + genop_1(s, OP_LE, cursp()); } else if (len == 1 && name[0] == '>') { - genop_2(s, OP_GT, cursp(), idx); + genop_1(s, OP_GT, cursp()); } else if (len == 2 && name[0] == '>' && name[1] == '=') { - genop_2(s, OP_GE, cursp(), idx); + genop_1(s, OP_GE, cursp()); } else { genop_3(s, OP_SEND, cursp(), idx, 1); diff --git a/src/symbol.c b/src/symbol.c index 6b4c7200c..f7dbc1be1 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -11,6 +11,7 @@ #include #include #include +#include /* ------------------------------------------------------ */ typedef struct symbol_name { @@ -170,10 +171,35 @@ mrb_free_symtbl(mrb_state *mrb) kh_destroy(n2s, mrb, mrb->name2sym); } +struct reserved_symbol_t { + mrb_reserved_symbol sym; + char const *str; +}; + +static struct reserved_symbol_t reserved_symbols[] = { + { mrb_sym_add, "+" }, + { mrb_sym_sub, "-" }, + { mrb_sym_mul, "*" }, + { mrb_sym_div, "/" }, + { mrb_sym_eq, "==" }, + { mrb_sym_lt, "<" }, + { mrb_sym_le, "<=" }, + { mrb_sym_gt, ">" }, + { mrb_sym_ge, ">=" }, + { mrb_sym_method_missing, "method_missing" }, + { 0, NULL }, +}; + void mrb_init_symtbl(mrb_state *mrb) { + int i; mrb->name2sym = kh_init(n2s, mrb); + + for (i = 0; reserved_symbols[i].sym != 0; ++i) { + mrb_sym s = mrb_intern_static(mrb, reserved_symbols[i].str, strlen(reserved_symbols[i].str)); + mrb_assert(s == reserved_symbols[i].sym); + } } /********************************************************************** diff --git a/src/vm.c b/src/vm.c index 067dd90f7..9792c3fbd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -21,6 +21,7 @@ #include #include "value_array.h" #include +#include #ifdef MRB_DISABLE_STDIO #if defined(__cplusplus) @@ -1009,6 +1010,7 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) uint32_t a; uint16_t b; uint8_t c; + mrb_sym mid; #ifdef DIRECT_THREADED static void *optable[] = { @@ -1386,9 +1388,18 @@ RETRY_TRY_BLOCK: SET_NIL_VALUE(regs[bidx]); goto L_SENDB; }; + L_SEND_CONSTSYM: + { + /* push nil after arguments */ + int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; + SET_NIL_VALUE(regs[bidx]); + goto L_SENDB_CONSTSYM; + }; CASE(OP_SENDB, BBB) L_SENDB: + mid = syms[b]; + L_SENDB_CONSTSYM: { int argc = (c == CALL_MAXARGS) ? -1 : c; int bidx = (argc < 0) ? a+2 : a+c+1; @@ -1396,7 +1407,6 @@ RETRY_TRY_BLOCK: struct RClass *cls; mrb_callinfo *ci = mrb->c->ci; mrb_value recv, blk; - mrb_sym mid = syms[b]; mrb_assert(bidx < irep->nregs); @@ -2204,7 +2214,7 @@ RETRY_TRY_BLOCK: v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ } while(0) - CASE(OP_ADD, BB) { + CASE(OP_ADD, B) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2259,13 +2269,14 @@ RETRY_TRY_BLOCK: break; default: c = 1; - goto L_SEND; + mid = mrb_sym_add; + goto L_SEND_CONSTSYM; } mrb_gc_arena_restore(mrb, ai); NEXT; } - CASE(OP_SUB, BB) { + CASE(OP_SUB, B) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2316,12 +2327,13 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - goto L_SEND; + mid = mrb_sym_sub; + goto L_SEND_CONSTSYM; } NEXT; } - CASE(OP_MUL, BB) { + CASE(OP_MUL, B) { /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): @@ -2372,12 +2384,13 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - goto L_SEND; + mid = mrb_sym_mul; + goto L_SEND_CONSTSYM; } NEXT; } - CASE(OP_DIV, BB) { + CASE(OP_DIV, B) { #ifndef MRB_WITHOUT_FLOAT double x, y, f; #endif @@ -2411,7 +2424,8 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - goto L_SEND; + mid = mrb_sym_div; + goto L_SEND_CONSTSYM; } #ifndef MRB_WITHOUT_FLOAT @@ -2509,7 +2523,7 @@ RETRY_TRY_BLOCK: #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) #ifdef MRB_WITHOUT_FLOAT -#define OP_CMP(op) do {\ +#define OP_CMP(op, sym) do {\ int result;\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ @@ -2518,7 +2532,8 @@ RETRY_TRY_BLOCK: break;\ default:\ c = 1;\ - goto L_SEND;\ + mid = mrb_sym_ ## sym;\ + goto L_SEND_CONSTSYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2528,7 +2543,7 @@ RETRY_TRY_BLOCK: }\ } while(0) #else -#define OP_CMP(op) do {\ +#define OP_CMP(op, sym) do {\ int result;\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ @@ -2546,7 +2561,8 @@ RETRY_TRY_BLOCK: break;\ default:\ c = 1;\ - goto L_SEND;\ + mid = mrb_sym_ ## sym;\ + goto L_SEND_CONSTSYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2557,33 +2573,33 @@ RETRY_TRY_BLOCK: } while(0) #endif - CASE(OP_EQ, BB) { + CASE(OP_EQ, B) { if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { SET_TRUE_VALUE(regs[a]); } else { - OP_CMP(==); + OP_CMP(==, eq); } NEXT; } - CASE(OP_LT, BB) { - OP_CMP(<); + CASE(OP_LT, B) { + OP_CMP(<, gt); NEXT; } - CASE(OP_LE, BB) { - OP_CMP(<=); + CASE(OP_LE, B) { + OP_CMP(<=, ge); NEXT; } - CASE(OP_GT, BB) { - OP_CMP(>); + CASE(OP_GT, B) { + OP_CMP(>, lt); NEXT; } - CASE(OP_GE, BB) { - OP_CMP(>=); + CASE(OP_GE, B) { + OP_CMP(>=, le); NEXT; } -- cgit v1.2.3 From e022080390107e6d746bc24a3651eb6b65daa509 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:22:43 +0900 Subject: Define null symbol --- include/mruby/symbol.h | 1 + src/symbol.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/mruby/symbol.h b/include/mruby/symbol.h index 595caeefd..f11346830 100644 --- a/include/mruby/symbol.h +++ b/include/mruby/symbol.h @@ -15,6 +15,7 @@ MRB_BEGIN_DECL typedef enum mrb_reserved_symbol { + mrb_sym_null = 0, // NULL symbol mrb_sym_add = 1, // + mrb_sym_sub = 2, // - mrb_sym_mul = 3, // * diff --git a/src/symbol.c b/src/symbol.c index f7dbc1be1..8ec300e20 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -187,7 +187,7 @@ static struct reserved_symbol_t reserved_symbols[] = { { mrb_sym_gt, ">" }, { mrb_sym_ge, ">=" }, { mrb_sym_method_missing, "method_missing" }, - { 0, NULL }, + { mrb_sym_null, NULL }, }; void @@ -196,7 +196,7 @@ mrb_init_symtbl(mrb_state *mrb) int i; mrb->name2sym = kh_init(n2s, mrb); - for (i = 0; reserved_symbols[i].sym != 0; ++i) { + for (i = 0; reserved_symbols[i].sym != mrb_sym_null; ++i) { mrb_sym s = mrb_intern_static(mrb, reserved_symbols[i].str, strlen(reserved_symbols[i].str)); mrb_assert(s == reserved_symbols[i].sym); } -- cgit v1.2.3 From 68714ab648356695bc235aaeb29fc43e8bad31d1 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:26:00 +0900 Subject: Fix SEGV --- src/vm.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 9792c3fbd..85e2f6c59 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2442,13 +2442,13 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI, BBB) { + CASE(OP_ADDI, BB) { /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = (mrb_int)c; + mrb_int y = (mrb_int)b; mrb_int z; if (mrb_int_add_overflow(x, y, &z)) { @@ -2465,22 +2465,23 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + c); + SET_FLOAT_VALUE(mrb, regs[a], x + b); } #else - mrb_float(regs[a]) += c; + mrb_float(regs[a]) += b; #endif break; #endif default: - SET_INT_VALUE(regs[a+1], c); + SET_INT_VALUE(regs[a+1], b); c = 1; - goto L_SEND; + mid = mrb_sym_add; + goto L_SEND_CONSTSYM; } NEXT; } - CASE(OP_SUBI, BBB) { + CASE(OP_SUBI, BB) { mrb_value *regs_a = regs + a; /* need to check if + is overridden */ @@ -2488,7 +2489,7 @@ RETRY_TRY_BLOCK: case MRB_TT_FIXNUM: { mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = (mrb_int)c; + mrb_int y = (mrb_int)b; mrb_int z; if (mrb_int_sub_overflow(x, y, &z)) { @@ -2505,17 +2506,18 @@ RETRY_TRY_BLOCK: #ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)c); + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); } #else - mrb_float(regs_a[0]) -= c; + mrb_float(regs_a[0]) -= b; #endif break; #endif default: - SET_INT_VALUE(regs_a[1], c); + SET_INT_VALUE(regs_a[1], b); c = 1; - goto L_SEND; + mid = mrb_sym_sub; + goto L_SEND_CONSTSYM; } NEXT; } -- cgit v1.2.3 From 557805da071e2dc685a7893107ca06a8e3787af0 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:29:43 +0900 Subject: Fix operator --- src/vm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 85e2f6c59..005396816 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2586,22 +2586,22 @@ RETRY_TRY_BLOCK: } CASE(OP_LT, B) { - OP_CMP(<, gt); + OP_CMP(<, lt); NEXT; } CASE(OP_LE, B) { - OP_CMP(<=, ge); + OP_CMP(<=, le); NEXT; } CASE(OP_GT, B) { - OP_CMP(>, lt); + OP_CMP(>, gt); NEXT; } CASE(OP_GE, B) { - OP_CMP(>=, le); + OP_CMP(>=, ge); NEXT; } -- cgit v1.2.3 From 486c9d902dfc525f5843dbd3d166e5ccf58e1c81 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Mon, 29 Oct 2018 19:35:31 +0900 Subject: Fix codedumper --- src/codedump.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/codedump.c b/src/codedump.c index 30a14f937..7d1950f75 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -328,38 +328,38 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_ALIAS, BB): printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b])); break; - CASE(OP_ADD, BB): - printf("OP_ADD\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_ADD, B): + printf("OP_ADD\tR%d\t\n", a); break; - CASE(OP_ADDI, BBB): - printf("OP_ADDI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + CASE(OP_ADDI, BB): + printf("OP_ADDI\tR%d\t%d\n", a, b); break; - CASE(OP_SUB, BB): - printf("OP_SUB\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_SUB, B): + printf("OP_SUB\tR%d\t\n", a); break; - CASE(OP_SUBI, BBB): - printf("OP_SUBI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); + CASE(OP_SUBI, BB): + printf("OP_SUBI\tR%d\t%d\n", a, b); break; - CASE(OP_MUL, BB): - printf("OP_MUL\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_MUL, B): + printf("OP_MUL\tR%d\t\n", a); break; - CASE(OP_DIV, BB): - printf("OP_DIV\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_DIV, B): + printf("OP_DIV\tR%d\t\n", a); break; - CASE(OP_LT, BB): - printf("OP_LT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_LT, B): + printf("OP_LT\t\tR%d\t\n", a); break; - CASE(OP_LE, BB): - printf("OP_LE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_LE, B): + printf("OP_LE\t\tR%d\t\n", a); break; - CASE(OP_GT, BB): - printf("OP_GT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_GT, B): + printf("OP_GT\t\tR%d\t\n", a); break; - CASE(OP_GE, BB): - printf("OP_GE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_GE, B): + printf("OP_GE\t\tR%d\t\n", a); break; - CASE(OP_EQ, BB): - printf("OP_EQ\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b])); + CASE(OP_EQ, B): + printf("OP_EQ\t\tR%d\t\n", a); break; CASE(OP_ARRAY, BB): printf("OP_ARRAY\tR%d\t%d\t", a, b); -- cgit v1.2.3 From 73727aeb50028830e9c70dcdbdc05b8bbbe6a688 Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Thu, 1 Nov 2018 11:10:47 +0900 Subject: Fixed a bug in INIT_DISPATCH for non direct threading; fix #4153 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 067dd90f7..28b375c68 100644 --- a/src/vm.c +++ b/src/vm.c @@ -935,7 +935,7 @@ argnum_error(mrb_state *mrb, mrb_int num) #ifndef DIRECT_THREADED -#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); pc++; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { +#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { #define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: #define NEXT break #define JUMP NEXT -- cgit v1.2.3 From d68da042b3666c1e46e4d3cf1a14e708df89f440 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 1 Nov 2018 22:33:15 +0900 Subject: The `env` object referenced from fibers may be freed; fix #4154 By dffa203 that reclaim `env` objects from heaps, there's more chance for `env` objects referenced from fibers may be freed from heap pages. --- src/gc.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index bacc322e8..a52c64bfa 100644 --- a/src/gc.c +++ b/src/gc.c @@ -274,9 +274,29 @@ mrb_free(mrb_state *mrb, void *p) (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); } +static mrb_bool +heap_p(mrb_gc *gc, struct RBasic *object) +{ + mrb_heap_page* page; + + page = gc->heaps; + while (page) { + RVALUE *p; + + p = objects(page); + if (&p[0].as.basic <= object && object <= &p[MRB_HEAP_PAGE_SIZE].as.basic) { + return TRUE; + } + page = page->next; + } + return FALSE; +} + MRB_API mrb_bool mrb_object_dead_p(mrb_state *mrb, struct RBasic *object) { - return is_dead(&mrb->gc, object); + mrb_gc *gc = &mrb->gc; + if (!heap_p(gc, object)) return TRUE; + return is_dead(gc, object); } static void @@ -807,7 +827,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) while (ce <= ci) { struct REnv *e = ci->env; - if (e && !is_dead(&mrb->gc, e) && + if (e && !mrb_object_dead_p(mrb, (struct RBasic*)e) && e->tt == MRB_TT_ENV && MRB_ENV_STACK_SHARED_P(e)) { mrb_env_unshare(mrb, e); } -- cgit v1.2.3 From 7ad53273a2c5346557a233d040ad233019c03277 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 1 Nov 2018 22:52:12 +0900 Subject: Silence Appveyor's VC compilation warnings. --- mrbgems/mruby-pack/src/pack.c | 2 +- mrbgems/mruby-sleep/src/mrb_sleep.c | 2 +- mrbgems/mruby-string-ext/src/string.c | 5 +++-- src/vm.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index f970d9339..796ba4d34 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -64,7 +64,7 @@ static int littleendian = 0; const static unsigned char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static signed char base64_dec_tab[128]; +static unsigned char base64_dec_tab[128]; static int diff --git a/mrbgems/mruby-sleep/src/mrb_sleep.c b/mrbgems/mruby-sleep/src/mrb_sleep.c index ce643cf12..0428f29eb 100644 --- a/mrbgems/mruby-sleep/src/mrb_sleep.c +++ b/mrbgems/mruby-sleep/src/mrb_sleep.c @@ -29,7 +29,7 @@ #ifdef _WIN32 #include #define sleep(x) Sleep(x * 1000) - #define usleep(x) Sleep(((x)<1000) ? 1 : ((x)/1000)) + #define usleep(x) Sleep((DWORD)((x)<1000) ? 1 : ((x)/1000)) #else #include #include diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 9fd84af7b..c0105fbd9 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -279,7 +279,7 @@ static struct tr_pattern* tr_parse_pattern(mrb_state *mrb, struct tr_pattern *ret, const mrb_value v_pattern, mrb_bool flag_reverse_enable) { const char *pattern = RSTRING_PTR(v_pattern); - int pattern_length = RSTRING_LEN(v_pattern); + mrb_int pattern_length = RSTRING_LEN(v_pattern); mrb_bool flag_reverse = FALSE; struct tr_pattern *pat1; int i = 0; @@ -438,7 +438,8 @@ str_tr(mrb_state *mrb, mrb_value str, mrb_value p1, mrb_value p2, mrb_bool squee mrb_raisef(mrb, E_ARGUMENT_ERROR, "character (%S) out of range", mrb_fixnum_value((mrb_int)c)); } - lastch = s[i] = c; + lastch = c; + s[i] = (char)c; } } } diff --git a/src/vm.c b/src/vm.c index 28b375c68..8157f6ca0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -186,7 +186,7 @@ stack_extend_alloc(mrb_state *mrb, mrb_int room) if (off > size) size = off; #ifdef MRB_STACK_EXTEND_DOUBLING - if (room <= (size_t)size) + if ((size_t)room <= size) size *= 2; else size += room; -- cgit v1.2.3 From 0419f07915603f74bbd3f6435ffee42cde5eaa5f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 2 Nov 2018 14:57:03 +0900 Subject: Add `NULL` checks for `mrb->ci` and `proc->upeer`; #4024 --- src/proc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/proc.c b/src/proc.c index 05b897480..dcbeb4f62 100644 --- a/src/proc.c +++ b/src/proc.c @@ -63,12 +63,12 @@ closure_setup(mrb_state *mrb, struct RProc *p) { mrb_callinfo *ci = mrb->c->ci; struct RProc *up = p->upper; - struct REnv *e; + struct REnv *e = NULL; - if (ci->env) { + if (ci && ci->env) { e = ci->env; } - else { + else if (up) { struct RClass *tc = MRB_PROC_TARGET_CLASS(p); e = env_new(mrb, up->body.irep->nlocals); @@ -78,9 +78,11 @@ closure_setup(mrb_state *mrb, struct RProc *p) mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc); } } - p->e.env = e; - p->flags |= MRB_PROC_ENVSET; - mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e); + if (e) { + p->e.env = e; + p->flags |= MRB_PROC_ENVSET; + mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)e); + } } struct RProc* -- cgit v1.2.3 From 659c680a5bbc04c736544741e2e16c27a3a3f374 Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Fri, 2 Nov 2018 15:34:35 +0900 Subject: Fix dump and load with endianess --- src/dump.c | 22 ++-------------------- src/load.c | 21 ++++----------------- 2 files changed, 6 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/dump.c b/src/dump.c index df1e171e4..0b1344594 100644 --- a/src/dump.c +++ b/src/dump.c @@ -85,26 +85,8 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ cur += write_padding(cur); - switch (flags & DUMP_ENDIAN_NAT) { - case DUMP_ENDIAN_BIG: - if (bigendian_p()) goto native; - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */ - } - break; - case DUMP_ENDIAN_LIL: - if (!bigendian_p()) goto native; - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint32l_to_bin(irep->iseq[iseq_no], cur); /* opcode */ - } - break; - - native: - case DUMP_ENDIAN_NAT: - memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); - cur += irep->ilen * sizeof(mrb_code); - break; - } + memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); + cur += irep->ilen * sizeof(mrb_code); return cur - buf; } diff --git a/src/load.c b/src/load.c index 54b50b14d..70f5406eb 100644 --- a/src/load.c +++ b/src/load.c @@ -83,23 +83,10 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag irep->flags |= MRB_ISEQ_NO_FREE; } else { - irep->iseq = (mrb_code *)mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen); - if (flags & FLAG_BYTEORDER_NATIVE) { - memcpy(irep->iseq, src, sizeof(uint32_t) * irep->ilen); - src += sizeof(uint32_t) * irep->ilen; - } - else if (flags & FLAG_BYTEORDER_BIG) { - for (i = 0; i < irep->ilen; i++) { - irep->iseq[i] = (mrb_code)bin_to_uint32(src); /* iseq */ - src += sizeof(uint32_t); - } - } - else { - for (i = 0; i < irep->ilen; i++) { - irep->iseq[i] = (mrb_code)bin_to_uint32l(src); /* iseq */ - src += sizeof(uint32_t); - } - } + size_t data_len = sizeof(mrb_code) * irep->ilen; + irep->iseq = (mrb_code *)mrb_malloc(mrb, data_len); + memcpy(irep->iseq, src, data_len); + src += data_len; } } -- cgit v1.2.3 From 57a435aa1d26c7d64c9d38c6865255a98e32d4cb Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Fri, 2 Nov 2018 15:49:34 +0900 Subject: Suppress warning --- src/dump.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/dump.c b/src/dump.c index 0b1344594..c2c334c9a 100644 --- a/src/dump.c +++ b/src/dump.c @@ -81,7 +81,6 @@ static ptrdiff_t write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) { uint8_t *cur = buf; - int iseq_no; cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ cur += write_padding(cur); -- cgit v1.2.3 From d9e253255218b04fd54a55980c4d8b6d61b1697c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 2 Nov 2018 22:58:12 +0900 Subject: Remove reserved symbols for now. It should be done by planned embedded symbols. --- include/mruby/symbol.h | 40 -------------------------- mrbgems/mruby-compiler/core/codegen.c | 12 +++----- src/symbol.c | 26 ----------------- src/vm.c | 53 +++++++++++++++++------------------ 4 files changed, 30 insertions(+), 101 deletions(-) delete mode 100644 include/mruby/symbol.h (limited to 'src') diff --git a/include/mruby/symbol.h b/include/mruby/symbol.h deleted file mode 100644 index b0feccc51..000000000 --- a/include/mruby/symbol.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -** mruby/symbol.h - symbol utilities -** -** See Copyright Notice in mruby.h -*/ - -#ifndef MRUBY_SYMBOL_H -#define MRUBY_SYMBOL_H - -#include "common.h" - -/** - * Symbol utilities - */ -MRB_BEGIN_DECL - -typedef enum mrb_reserved_symbol { - mrb_sym_null = 0, // NULL symbol - - mrb_sym_add = 1, // + - mrb_sym_sub = 2, // - - mrb_sym_mul = 3, // * - mrb_sym_div = 4, // / - mrb_sym_eq = 5, // == - mrb_sym_lt = 6, // < - mrb_sym_le = 7, // <= - mrb_sym_gt = 8, // > - mrb_sym_ge = 9, // >= - - mrb_sym_method_missing = 10, // method_missing -} mrb_reserved_symbol; - -static inline mrb_bool -mrb_symbol_constsym_send_p(mrb_sym sym) { - return mrb_sym_add <= sym && sym <= mrb_sym_ge; -} - -MRB_END_DECL - -#endif /* MRUBY_SYMBOL_H */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 22ac51239..22ad3253b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -18,7 +18,6 @@ #include #include #include -#include #ifndef MRB_CODEGEN_LEVEL_MAX #define MRB_CODEGEN_LEVEL_MAX 1024 @@ -974,7 +973,7 @@ static void gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) { mrb_sym sym = name ? name : nsym(tree->cdr->car); - int idx, skip = 0; + int skip = 0; int n = 0, noop = 0, sendv = 0, blk = 0; codegen(s, tree->car, VAL); /* receiver */ @@ -983,9 +982,6 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) gen_move(s, cursp(), recv, 1); skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val); } - if (!mrb_symbol_constsym_send_p(sym)) { - idx = new_sym(s, sym); - } tree = tree->cdr->cdr->car; if (tree) { n = gen_values(s, tree->car, VAL, sp?1:0); @@ -1047,6 +1043,8 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) genop_1(s, OP_EQ, cursp()); } else { + int idx = new_sym(s, sym); + if (sendv) { genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx); } @@ -2026,9 +2024,6 @@ codegen(codegen_scope *s, node *tree, int val) push(); pop(); pop(); pop(); - if (!mrb_symbol_constsym_send_p(sym)) { - idx = new_sym(s, sym); - } if (len == 1 && name[0] == '+') { gen_addsub(s, OP_ADD, cursp()); } @@ -2054,6 +2049,7 @@ codegen(codegen_scope *s, node *tree, int val) genop_1(s, OP_GE, cursp()); } else { + idx = new_sym(s, sym); genop_3(s, OP_SEND, cursp(), idx, 1); } if (callargs < 0) { diff --git a/src/symbol.c b/src/symbol.c index 8ec300e20..6b4c7200c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -11,7 +11,6 @@ #include #include #include -#include /* ------------------------------------------------------ */ typedef struct symbol_name { @@ -171,35 +170,10 @@ mrb_free_symtbl(mrb_state *mrb) kh_destroy(n2s, mrb, mrb->name2sym); } -struct reserved_symbol_t { - mrb_reserved_symbol sym; - char const *str; -}; - -static struct reserved_symbol_t reserved_symbols[] = { - { mrb_sym_add, "+" }, - { mrb_sym_sub, "-" }, - { mrb_sym_mul, "*" }, - { mrb_sym_div, "/" }, - { mrb_sym_eq, "==" }, - { mrb_sym_lt, "<" }, - { mrb_sym_le, "<=" }, - { mrb_sym_gt, ">" }, - { mrb_sym_ge, ">=" }, - { mrb_sym_method_missing, "method_missing" }, - { mrb_sym_null, NULL }, -}; - void mrb_init_symtbl(mrb_state *mrb) { - int i; mrb->name2sym = kh_init(n2s, mrb); - - for (i = 0; reserved_symbols[i].sym != mrb_sym_null; ++i) { - mrb_sym s = mrb_intern_static(mrb, reserved_symbols[i].str, strlen(reserved_symbols[i].str)); - mrb_assert(s == reserved_symbols[i].sym); - } } /********************************************************************** diff --git a/src/vm.c b/src/vm.c index 627eb9325..9844d3e60 100644 --- a/src/vm.c +++ b/src/vm.c @@ -21,7 +21,6 @@ #include #include "value_array.h" #include -#include #ifdef MRB_DISABLE_STDIO #if defined(__cplusplus) @@ -1388,18 +1387,18 @@ RETRY_TRY_BLOCK: SET_NIL_VALUE(regs[bidx]); goto L_SENDB; }; - L_SEND_CONSTSYM: + L_SEND_SYM: { /* push nil after arguments */ int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1; SET_NIL_VALUE(regs[bidx]); - goto L_SENDB_CONSTSYM; + goto L_SENDB_SYM; }; CASE(OP_SENDB, BBB) L_SENDB: mid = syms[b]; - L_SENDB_CONSTSYM: + L_SENDB_SYM: { int argc = (c == CALL_MAXARGS) ? -1 : c; int bidx = (argc < 0) ? a+2 : a+c+1; @@ -2269,8 +2268,8 @@ RETRY_TRY_BLOCK: break; default: c = 1; - mid = mrb_sym_add; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "+"); + goto L_SEND_SYM; } mrb_gc_arena_restore(mrb, ai); NEXT; @@ -2327,8 +2326,8 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - mid = mrb_sym_sub; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "-"); + goto L_SEND_SYM; } NEXT; } @@ -2384,8 +2383,8 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - mid = mrb_sym_mul; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "*"); + goto L_SEND_SYM; } NEXT; } @@ -2424,8 +2423,8 @@ RETRY_TRY_BLOCK: #endif default: c = 1; - mid = mrb_sym_div; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "/"); + goto L_SEND_SYM; } #ifndef MRB_WITHOUT_FLOAT @@ -2475,8 +2474,8 @@ RETRY_TRY_BLOCK: default: SET_INT_VALUE(regs[a+1], b); c = 1; - mid = mrb_sym_add; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "+"); + goto L_SEND_SYM; } NEXT; } @@ -2516,8 +2515,8 @@ RETRY_TRY_BLOCK: default: SET_INT_VALUE(regs_a[1], b); c = 1; - mid = mrb_sym_sub; - goto L_SEND_CONSTSYM; + mid = mrb_intern_lit(mrb, "-"); + goto L_SEND_SYM; } NEXT; } @@ -2525,7 +2524,7 @@ RETRY_TRY_BLOCK: #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) #ifdef MRB_WITHOUT_FLOAT -#define OP_CMP(op, sym) do {\ +#define OP_CMP(op) do {\ int result;\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ @@ -2534,8 +2533,8 @@ RETRY_TRY_BLOCK: break;\ default:\ c = 1;\ - mid = mrb_sym_ ## sym;\ - goto L_SEND_CONSTSYM;\ + mid = mrb_intern_lit(mrb, # op);\ + goto L_SEND_SYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2545,7 +2544,7 @@ RETRY_TRY_BLOCK: }\ } while(0) #else -#define OP_CMP(op, sym) do {\ +#define OP_CMP(op) do {\ int result;\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ @@ -2563,8 +2562,8 @@ RETRY_TRY_BLOCK: break;\ default:\ c = 1;\ - mid = mrb_sym_ ## sym;\ - goto L_SEND_CONSTSYM;\ + mid = mrb_intern_lit(mrb, # op);\ + goto L_SEND_SYM;\ }\ if (result) {\ SET_TRUE_VALUE(regs[a]);\ @@ -2580,28 +2579,28 @@ RETRY_TRY_BLOCK: SET_TRUE_VALUE(regs[a]); } else { - OP_CMP(==, eq); + OP_CMP(==); } NEXT; } CASE(OP_LT, B) { - OP_CMP(<, lt); + OP_CMP(<); NEXT; } CASE(OP_LE, B) { - OP_CMP(<=, le); + OP_CMP(<=); NEXT; } CASE(OP_GT, B) { - OP_CMP(>, gt); + OP_CMP(>); NEXT; } CASE(OP_GE, B) { - OP_CMP(>=, ge); + OP_CMP(>=); NEXT; } -- cgit v1.2.3 From d47003aea406e1e48ef79efd61b17d5121c4c6b9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 5 Nov 2018 07:44:25 +0900 Subject: Fixed a bug in argument number check with kwargs; fix #4159 --- src/vm.c | 11 ++++------- test/t/syntax.rb | 4 ++++ 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 9844d3e60..19288245c 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1780,11 +1780,9 @@ RETRY_TRY_BLOCK: /* strict argument check */ if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) { - if (argc >= 0 && !(argc <= 1 && kd)) { - if (argc < m1 + m2 + kd || (r == 0 && argc > len + kd)) { - argnum_error(mrb, m1+m2); - goto L_RAISE; - } + if (argc < m1 + m2 || (r == 0 && argc > len + kd)) { + argnum_error(mrb, m1+m2); + goto L_RAISE; } } /* extract first argument array to arguments */ @@ -1810,8 +1808,7 @@ RETRY_TRY_BLOCK: kargs = 0; } else { - mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments"); - mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); + argnum_error(mrb, m1+m2); goto L_RAISE; } if (MRB_ASPEC_KEY(a) > 0) { diff --git a/test/t/syntax.rb b/test/t/syntax.rb index 883cbd1ba..603547c7c 100644 --- a/test/t/syntax.rb +++ b/test/t/syntax.rb @@ -471,6 +471,10 @@ this is a comment that has extra after =begin and =end with tabs after it end assert 'keyword arguments' do + def m(a, b:1) [a, b] end + assert_equal [1, 1], m(1) + assert_equal [1, 2], m(1, b: 2) + def m(a, b:) [a, b] end assert_equal [1, 2], m(1, b: 2) assert_raise(ArgumentError) { m b: 1 } -- cgit v1.2.3 From d25ebec988f61f60d181f38dad9057243034eb10 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 5 Nov 2018 21:52:17 +0900 Subject: Fixed wrong `ArgumentError` with keyword arguments; fix #4159 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 19288245c..5779791bc 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1803,7 +1803,7 @@ RETRY_TRY_BLOCK: kdict = argv[argc-1]; mrb_hash_check_kdict(mrb, kdict); } - else if (r) { + else if (r || argc <= m1+m2+o) { kdict = mrb_hash_new(mrb); kargs = 0; } -- cgit v1.2.3 From 7d7f9feee7302ffabb04fa6ea9fb4e46db5682a2 Mon Sep 17 00:00:00 2001 From: Hiroshi Mimaki Date: Wed, 7 Nov 2018 17:20:18 +0900 Subject: Wrong pool data length for negative floating value in a mrb file. --- src/fmt_fp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 783cc6c02..7028d3aac 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -379,7 +379,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) { - char buf[24]; + char buf[25]; snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); return mrb_str_new_cstr(mrb, buf); -- cgit v1.2.3 From 1bea1e2050ee4c1b3e558a307c7d2731f6b52823 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 19:24:45 +0900 Subject: Small renaming refactor in `dump.c` --- src/dump.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/dump.c b/src/dump.c index c2c334c9a..e41dd83ed 100644 --- a/src/dump.c +++ b/src/dump.c @@ -838,26 +838,26 @@ write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8 } static mrb_bool -is_debug_info_defined(mrb_irep *irep) +debug_info_defined_p(mrb_irep *irep) { int i; if (!irep->debug_info) return FALSE; for (i=0; irlen; i++) { - if (!is_debug_info_defined(irep->reps[i])) return FALSE; + if (!debug_info_defined_p(irep->reps[i])) return FALSE; } return TRUE; } static mrb_bool -is_lv_defined(mrb_irep *irep) +lv_defined_p(mrb_irep *irep) { int i; if (irep->lv) { return TRUE; } for (i = 0; i < irep->rlen; ++i) { - if (is_lv_defined(irep->reps[i])) { return TRUE; } + if (lv_defined_p(irep->reps[i])) { return TRUE; } } return FALSE; @@ -886,7 +886,7 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * size_t section_irep_size; size_t section_lineno_size = 0, section_lv_size = 0; uint8_t *cur = NULL; - mrb_bool const debug_info_defined = is_debug_info_defined(irep), lv_defined = is_lv_defined(irep); + mrb_bool const debug_info_defined = debug_info_defined_p(irep), lv_defined = lv_defined_p(irep); mrb_sym *lv_syms = NULL; uint32_t lv_syms_len = 0; mrb_sym *filenames = NULL; uint16_t filenames_len = 0; -- cgit v1.2.3 From 61f49690e43cea3df6ebbdf424cf6777826056b0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 20:15:10 +0900 Subject: Remove `filename`&`lines` from `mrb_irep` struct. This patch slightly reduce memory consumption (2% for my test). --- include/mruby/debug.h | 5 +- include/mruby/irep.h | 3 - mrbgems/mruby-compiler/core/codegen.c | 38 +++-------- src/debug.c | 32 ++++----- src/dump.c | 125 +--------------------------------- src/load.c | 10 +-- src/state.c | 5 -- 7 files changed, 30 insertions(+), 188 deletions(-) (limited to 'src') diff --git a/include/mruby/debug.h b/include/mruby/debug.h index d1de34882..f0a40dfcf 100644 --- a/include/mruby/debug.h +++ b/include/mruby/debug.h @@ -55,10 +55,11 @@ MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc); */ MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc); +MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file( - mrb_state *mrb, mrb_irep *irep, + mrb_state *mrb, mrb_irep_debug_info *info, + const char *filename, uint16_t *lines, uint32_t start_pos, uint32_t end_pos); -MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); MRB_API void mrb_debug_info_free(mrb_state *mrb, mrb_irep_debug_info *d); MRB_END_DECL diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 76bafb25c..78cbc2b74 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -39,9 +39,6 @@ typedef struct mrb_irep { struct mrb_locals *lv; /* debug info */ - mrb_bool own_filename; - const char *filename; - uint16_t *lines; struct mrb_irep_debug_info* debug_info; uint16_t ilen, plen, slen, rlen; diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 22ad3253b..dbd3b8ecf 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -124,15 +124,6 @@ codegen_palloc(codegen_scope *s, size_t len) return p; } -static void* -codegen_malloc(codegen_scope *s, size_t len) -{ - void *p = mrb_malloc_simple(s->mrb, len); - - if (!p) codegen_error(s, "mrb_malloc"); - return p; -} - static void* codegen_realloc(codegen_scope *s, void *p, size_t len) { @@ -162,7 +153,6 @@ emit_B(codegen_scope *s, uint32_t pc, uint8_t i) s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa); if (s->lines) { s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa); - s->irep->lines = s->lines; } } if (s->lines) { @@ -1371,8 +1361,10 @@ codegen(codegen_scope *s, node *tree, int val) codegen_error(s, "too complex expression"); } if (s->irep && s->filename_index != tree->filename_index) { - s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); - mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc); + const char *filename = mrb_parser_get_filename(s->parser, s->filename_index); + + mrb_debug_info_append_file(s->mrb, s->irep->debug_info, + filename, s->lines, s->debug_start_pos, s->pc); s->debug_start_pos = s->pc; s->filename_index = tree->filename_index; s->filename = mrb_parser_get_filename(s->parser, tree->filename_index); @@ -2965,8 +2957,6 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) p->debug_start_pos = 0; if (p->filename) { mrb_debug_info_alloc(mrb, p->irep); - p->irep->filename = p->filename; - p->irep->lines = p->lines; } else { p->irep->debug_info = NULL; @@ -2984,34 +2974,22 @@ scope_finish(codegen_scope *s) { mrb_state *mrb = s->mrb; mrb_irep *irep = s->irep; - size_t fname_len; - char *fname; irep->flags = 0; if (s->iseq) { irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); irep->ilen = s->pc; - if (s->lines) { - irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc); - } - else { - irep->lines = 0; - } } irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen); irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen); irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen); if (s->filename) { - irep->filename = mrb_parser_get_filename(s->parser, s->filename_index); - mrb_debug_info_append_file(mrb, irep, s->debug_start_pos, s->pc); + const char *filename = mrb_parser_get_filename(s->parser, s->filename_index); - fname_len = strlen(s->filename); - fname = (char*)codegen_malloc(s, fname_len + 1); - memcpy(fname, s->filename, fname_len); - fname[fname_len] = '\0'; - irep->filename = fname; - irep->own_filename = TRUE; + mrb_debug_info_append_file(s->mrb, s->irep->debug_info, + filename, s->lines, s->debug_start_pos, s->pc); } + mrb_free(s->mrb, s->lines); irep->nlocals = s->nlocals; irep->nregs = s->nregs; diff --git a/src/debug.c b/src/debug.c index e55f11d4f..207065d9e 100644 --- a/src/debug.c +++ b/src/debug.c @@ -55,7 +55,7 @@ mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; - if (!irep->debug_info) { return irep->filename; } + if (!irep->debug_info) return NULL; else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { return f->filename; } @@ -69,7 +69,7 @@ mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc) if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; if (!irep->debug_info) { - return irep->lines? irep->lines[pc] : -1; + return -1; } else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { switch (f->line_type) { @@ -122,24 +122,22 @@ mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) } MRB_API mrb_irep_debug_info_file* -mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, +mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *info, + const char *filename, uint16_t *lines, uint32_t start_pos, uint32_t end_pos) { - mrb_irep_debug_info *info; mrb_irep_debug_info_file *ret; uint32_t file_pc_count; size_t fn_len; mrb_int len; uint32_t i; - if (!irep->debug_info) { return NULL; } + if (!info) { return NULL; } - mrb_assert(irep->filename); - mrb_assert(irep->lines); + mrb_assert(filename); + mrb_assert(lines); - info = irep->debug_info; - - if (info->flen > 0 && strcmp(irep->filename, info->files[info->flen - 1]->filename) == 0) { + if (info->flen > 0 && strcmp(filename, info->files[info->flen - 1]->filename) == 0) { return NULL; } @@ -156,12 +154,12 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, ret->start_pos = start_pos; info->pc_count = end_pos; - fn_len = strlen(irep->filename); - ret->filename_sym = mrb_intern(mrb, irep->filename, fn_len); + fn_len = strlen(filename); + ret->filename_sym = mrb_intern(mrb, filename, fn_len); len = 0; ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len); - ret->line_type = select_line_type(irep->lines + start_pos, end_pos - start_pos); + ret->line_type = select_line_type(lines + start_pos, end_pos - start_pos); ret->lines.ptr = NULL; switch (ret->line_type) { @@ -169,7 +167,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, ret->line_entry_count = file_pc_count; ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); for (i = 0; i < file_pc_count; ++i) { - ret->lines.ary[i] = irep->lines[start_pos + i]; + ret->lines.ary[i] = lines[start_pos + i]; } break; @@ -179,18 +177,18 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep *irep, ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); ret->line_entry_count = 0; for (i = 0; i < file_pc_count; ++i) { - if (irep->lines[start_pos + i] == prev_line) { continue; } + if (lines[start_pos + i] == prev_line) { continue; } ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( mrb, ret->lines.flat_map, sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1)); m.start_pos = start_pos + i; - m.line = irep->lines[start_pos + i]; + m.line = lines[start_pos + i]; ret->lines.flat_map[ret->line_entry_count] = m; /* update */ ++ret->line_entry_count; - prev_line = irep->lines[start_pos + i]; + prev_line = lines[start_pos + i]; } } break; diff --git a/src/dump.c b/src/dump.c index e41dd83ed..6ce9c4eb9 100644 --- a/src/dump.c +++ b/src/dump.c @@ -353,118 +353,6 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, return MRB_DUMP_OK; } -static int -write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin) -{ - struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin; - - memcpy(header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(header->section_ident)); - uint32_to_bin((uint32_t)section_size, header->section_size); - - return MRB_DUMP_OK; -} - -static size_t -get_lineno_record_size(mrb_state *mrb, mrb_irep *irep) -{ - size_t size = 0; - - size += sizeof(uint32_t); /* record size */ - size += sizeof(uint16_t); /* filename size */ - if (irep->filename) { - size += strlen(irep->filename); /* filename */ - } - size += sizeof(uint32_t); /* niseq */ - if (irep->lines) { - size += sizeof(uint16_t) * irep->ilen; /* lineno */ - } - - return size; -} - -static size_t -write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) -{ - uint8_t *cur = bin; - int iseq_no; - size_t filename_len; - ptrdiff_t diff; - - cur += sizeof(uint32_t); /* record size */ - - if (irep->filename) { - filename_len = strlen(irep->filename); - } - else { - filename_len = 0; - } - mrb_assert_int_fit(size_t, filename_len, uint16_t, UINT16_MAX); - cur += uint16_to_bin((uint16_t)filename_len, cur); /* filename size */ - - if (filename_len) { - memcpy(cur, irep->filename, filename_len); - cur += filename_len; /* filename */ - } - - if (irep->lines) { - mrb_assert_int_fit(size_t, irep->ilen, uint32_t, UINT32_MAX); - cur += uint32_to_bin((uint32_t)(irep->ilen), cur); /* niseq */ - for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) { - cur += uint16_to_bin(irep->lines[iseq_no], cur); /* opcode */ - } - } - else { - cur += uint32_to_bin(0, cur); /* niseq */ - } - - diff = cur - bin; - mrb_assert_int_fit(ptrdiff_t, diff, uint32_t, UINT32_MAX); - - uint32_to_bin((uint32_t)diff, bin); /* record size */ - - mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX); - return (size_t)diff; -} - -static size_t -write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin) -{ - size_t rlen, size = 0; - int i; - - rlen = write_lineno_record_1(mrb, irep, bin); - bin += rlen; - size += rlen; - for (i=0; irlen; i++) { - rlen = write_lineno_record(mrb, irep, bin); - bin += rlen; - size += rlen; - } - return size; -} - -static int -write_section_lineno(mrb_state *mrb, mrb_irep *irep, uint8_t *bin) -{ - size_t section_size = 0; - size_t rlen = 0; /* size of irep record */ - uint8_t *cur = bin; - - if (mrb == NULL || bin == NULL) { - return MRB_DUMP_INVALID_ARGUMENT; - } - - cur += sizeof(struct rite_section_lineno_header); - section_size += sizeof(struct rite_section_lineno_header); - - rlen = write_lineno_record(mrb, irep, cur); - section_size += rlen; - - write_section_lineno_header(mrb, section_size, bin); - - return MRB_DUMP_OK; -} - static size_t get_debug_record_size(mrb_state *mrb, mrb_irep *irep) { @@ -911,10 +799,6 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * section_lineno_size += get_debug_record_size(mrb, irep); } - else { - section_lineno_size += sizeof(struct rite_section_lineno_header); - section_lineno_size += get_lineno_record_size(mrb, irep); - } } if (lv_defined) { @@ -942,12 +826,9 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, uint8_t flags, uint8_t **bin, size_t * if (flags & DUMP_DEBUG_INFO) { if (debug_info_defined) { result = write_section_debug(mrb, irep, cur, filenames, filenames_len); - } - else { - result = write_section_lineno(mrb, irep, cur); - } - if (result != MRB_DUMP_OK) { - goto error_exit; + if (result != MRB_DUMP_OK) { + goto error_exit; + } } cur += section_lineno_size; } diff --git a/src/load.c b/src/load.c index 70f5406eb..559fff1d4 100644 --- a/src/load.c +++ b/src/load.c @@ -215,12 +215,11 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return read_irep_record(mrb, bin, &len, flags); } +/* ignore lineno record */ static int read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len) { size_t i, fname_len, niseq; - char *fname; - uint16_t *lines; *len = 0; bin += sizeof(uint32_t); /* record size */ @@ -228,9 +227,6 @@ read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t fname_len = bin_to_uint16(bin); bin += sizeof(uint16_t); *len += sizeof(uint16_t); - fname = (char *)mrb_malloc(mrb, fname_len + 1); - memcpy(fname, bin, fname_len); - fname[fname_len] = '\0'; bin += fname_len; *len += fname_len; @@ -241,15 +237,11 @@ read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) { return MRB_DUMP_GENERAL_FAILURE; } - lines = (uint16_t *)mrb_malloc(mrb, niseq * sizeof(uint16_t)); for (i = 0; i < niseq; i++) { - lines[i] = bin_to_uint16(bin); bin += sizeof(uint16_t); /* niseq */ *len += sizeof(uint16_t); } - irep->filename = fname; - irep->lines = lines; return MRB_DUMP_OK; } diff --git a/src/state.c b/src/state.c index 18d104555..5583a77e5 100644 --- a/src/state.c +++ b/src/state.c @@ -168,10 +168,6 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) } mrb_free(mrb, irep->reps); mrb_free(mrb, irep->lv); - if (irep->own_filename) { - mrb_free(mrb, (void *)irep->filename); - } - mrb_free(mrb, irep->lines); mrb_debug_info_free(mrb, irep->debug_info); mrb_free(mrb, irep); } @@ -273,7 +269,6 @@ mrb_add_irep(mrb_state *mrb) irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep)); *irep = mrb_irep_zero; irep->refcnt = 1; - irep->own_filename = FALSE; return irep; } -- cgit v1.2.3 From f39f428ed4cce826e3cc1e59a323369a2932ed75 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 20:58:36 +0900 Subject: Silence `-fsanitize=undefined` warning in `src/enum.c`; fix #4161 --- src/enum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/enum.c b/src/enum.c index 03508953e..38f004f51 100644 --- a/src/enum.c +++ b/src/enum.c @@ -30,7 +30,7 @@ enum_update_hash(mrb_state *mrb, mrb_value self) /* not reached */ hv = 0; } - hash ^= (hv << (index % 16)); + hash ^= ((uint32_t)hv << (index % 16)); return mrb_fixnum_value(hash); } -- cgit v1.2.3 From 56db3cf3eb35e430f73d31468b8cad37e21538c7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 21:01:25 +0900 Subject: Simplify argument parsing; ref #4161 --- src/enum.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'src') diff --git a/src/enum.c b/src/enum.c index 38f004f51..1e9445176 100644 --- a/src/enum.c +++ b/src/enum.c @@ -14,22 +14,8 @@ enum_update_hash(mrb_state *mrb, mrb_value self) mrb_int hash; mrb_int index; mrb_int hv; - mrb_value item_hash; - mrb_get_args(mrb, "iio", &hash, &index, &item_hash); - if (mrb_fixnum_p(item_hash)) { - hv = mrb_fixnum(item_hash); - } -#ifndef MRB_WITHOUT_FLOAT - else if (mrb_float_p(item_hash)) { - hv = (mrb_int)mrb_float(item_hash); - } -#endif - else { - mrb_raise(mrb, E_TYPE_ERROR, "can't calculate hash"); - /* not reached */ - hv = 0; - } + mrb_get_args(mrb, "iii", &hash, &index, &hv); hash ^= ((uint32_t)hv << (index % 16)); return mrb_fixnum_value(hash); -- cgit v1.2.3 From faf51f82c7265f2cbdda8291429d7f2016d2bc3f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 23:28:34 +0900 Subject: Rename local variables in `mrb_debug_info_append_file` --- src/debug.c | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/debug.c b/src/debug.c index 207065d9e..2949131e4 100644 --- a/src/debug.c +++ b/src/debug.c @@ -122,72 +122,72 @@ mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep) } MRB_API mrb_irep_debug_info_file* -mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *info, +mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, const char *filename, uint16_t *lines, uint32_t start_pos, uint32_t end_pos) { - mrb_irep_debug_info_file *ret; + mrb_irep_debug_info_file *f; uint32_t file_pc_count; size_t fn_len; mrb_int len; uint32_t i; - if (!info) { return NULL; } + if (!d) return NULL; + if (start_pos == end_pos) return NULL; mrb_assert(filename); mrb_assert(lines); - if (info->flen > 0 && strcmp(filename, info->files[info->flen - 1]->filename) == 0) { + if (d->flen > 0 && strcmp(filename, d->files[d->flen - 1]->filename) == 0) { return NULL; } - ret = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*ret)); - info->files = - (mrb_irep_debug_info_file**)( - info->files - ? mrb_realloc(mrb, info->files, sizeof(mrb_irep_debug_info_file*) * (info->flen + 1)) + f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f)); + d->files = (mrb_irep_debug_info_file**)( + d->files + ? mrb_realloc(mrb, d->files, sizeof(mrb_irep_debug_info_file*) * (d->flen + 1)) : mrb_malloc(mrb, sizeof(mrb_irep_debug_info_file*))); - info->files[info->flen++] = ret; + d->files[d->flen++] = f; file_pc_count = end_pos - start_pos; - ret->start_pos = start_pos; - info->pc_count = end_pos; + f->start_pos = start_pos; + d->pc_count = end_pos; fn_len = strlen(filename); - ret->filename_sym = mrb_intern(mrb, filename, fn_len); + f->filename_sym = mrb_intern(mrb, filename, fn_len); len = 0; - ret->filename = mrb_sym2name_len(mrb, ret->filename_sym, &len); + f->filename = mrb_sym2name_len(mrb, f->filename_sym, &len); - ret->line_type = select_line_type(lines + start_pos, end_pos - start_pos); - ret->lines.ptr = NULL; + f->line_type = select_line_type(lines + start_pos, end_pos - start_pos); + f->lines.ptr = NULL; - switch (ret->line_type) { + switch (f->line_type) { case mrb_debug_line_ary: - ret->line_entry_count = file_pc_count; - ret->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); + f->line_entry_count = file_pc_count; + f->lines.ary = (uint16_t*)mrb_malloc(mrb, sizeof(uint16_t) * file_pc_count); for (i = 0; i < file_pc_count; ++i) { - ret->lines.ary[i] = lines[start_pos + i]; + f->lines.ary[i] = lines[start_pos + i]; } break; case mrb_debug_line_flat_map: { uint16_t prev_line = 0; mrb_irep_debug_info_line m; - ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); - ret->line_entry_count = 0; + f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_malloc(mrb, sizeof(mrb_irep_debug_info_line) * 1); + f->line_entry_count = 0; for (i = 0; i < file_pc_count; ++i) { if (lines[start_pos + i] == prev_line) { continue; } - ret->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( - mrb, ret->lines.flat_map, - sizeof(mrb_irep_debug_info_line) * (ret->line_entry_count + 1)); + f->lines.flat_map = (mrb_irep_debug_info_line*)mrb_realloc( + mrb, f->lines.flat_map, + sizeof(mrb_irep_debug_info_line) * (f->line_entry_count + 1)); m.start_pos = start_pos + i; m.line = lines[start_pos + i]; - ret->lines.flat_map[ret->line_entry_count] = m; + f->lines.flat_map[f->line_entry_count] = m; /* update */ - ++ret->line_entry_count; + ++f->line_entry_count; prev_line = lines[start_pos + i]; } } break; @@ -195,7 +195,7 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *info, default: mrb_assert(0); break; } - return ret; + return f; } MRB_API void -- cgit v1.2.3 From 0a022f7b8d3e6abc0320001430de9e7d63ba9212 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 15 Nov 2018 23:31:29 +0900 Subject: The saved `pc` from `ERR_PC_SET` was wrong; fix #4138 The saving `pc` position should be beginning of the instruction. But after `mruby 2.0` byte code modification, the `pc` variable points the beginning of the next instruction. We save the previous position in a local variable `pc0`. --- src/vm.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 5779791bc..2b88b0761 100644 --- a/src/vm.c +++ b/src/vm.c @@ -913,8 +913,8 @@ argnum_error(mrb_state *mrb, mrb_int num) mrb_exc_set(mrb, exc); } -#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc; -#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; +#define ERR_PC_SET(mrb) mrb->c->ci->err = pc0; +#define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; #ifdef MRB_ENABLE_DEBUG_HOOK #define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs)); #else @@ -936,7 +936,7 @@ argnum_error(mrb_state *mrb, mrb_int num) #ifndef DIRECT_THREADED #define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) { -#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: +#define CASE(insn,ops) case insn: pc0=pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY: #define NEXT break #define JUMP NEXT #define END_DISPATCH }} @@ -944,7 +944,7 @@ argnum_error(mrb_state *mrb, mrb_int num) #else #define INIT_DISPATCH JUMP; return mrb_nil_value(); -#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); L_ ## insn ## _BODY: +#define CASE(insn,ops) L_ ## insn: pc0=pc++; FETCH_ ## ops (); L_ ## insn ## _BODY: #define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn] #define JUMP NEXT @@ -999,6 +999,7 @@ MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { /* mrb_assert(mrb_proc_cfunc_p(proc)) */ + mrb_code *pc0 = pc; mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; @@ -1144,7 +1145,7 @@ RETRY_TRY_BLOCK: CASE(OP_GETCV, BB) { mrb_value val; - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); val = mrb_vm_cv_get(mrb, syms[b]); ERR_PC_CLR(mrb); regs[a] = val; @@ -1160,7 +1161,7 @@ RETRY_TRY_BLOCK: mrb_value val; mrb_sym sym = syms[b]; - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); val = mrb_vm_const_get(mrb, sym); ERR_PC_CLR(mrb); regs[a] = val; @@ -1175,7 +1176,7 @@ RETRY_TRY_BLOCK: CASE(OP_GETMCNST, BB) { mrb_value val; - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); val = mrb_const_get(mrb, regs[a], syms[b]); ERR_PC_CLR(mrb); regs[a] = val; @@ -1424,7 +1425,7 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) { mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1); - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); mrb_method_missing(mrb, mid, recv, args); } if (argc >= 0) { @@ -1621,7 +1622,7 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &cls, missing); if (MRB_METHOD_UNDEF_P(m)) { mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); mrb_method_missing(mrb, mid, recv, args); } mid = missing; @@ -2925,7 +2926,7 @@ RETRY_TRY_BLOCK: mrb_value exc; exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); - ERR_PC_SET(mrb, pc); + ERR_PC_SET(mrb); mrb_exc_set(mrb, exc); goto L_RAISE; } -- cgit v1.2.3 From 180b73fec437e21e2e862fc47bff9ad07f581d2c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 16 Nov 2018 01:04:57 +0900 Subject: The key or value object could be reclaimed by GC; fix #4164 The GC may occur between `sg_shift` and `mrb_assoc_new`, in which case `key` and `value` could be freed even tough they are still alive. The issue is found and fixed by https://hackerone.com/hexodus --- src/hash.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 03a95dbd8..376c054cb 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1057,6 +1057,8 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_value del_key, del_val; sg_shift(mrb, sg, &del_key, &del_val); + mrb_gc_protect(mrb, del_key); + mrb_gc_protect(mrb, del_val); return mrb_assoc_new(mrb, del_key, del_val); } -- cgit v1.2.3 From 25d390d6ccf3da7a853ddd8272dd318ecadca316 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 09:30:15 +0900 Subject: Improve Hash table using variable sized segments. --- include/mruby/hash.h | 2 +- src/hash.c | 308 +++++++++++++++++++++++++++------------------------ 2 files changed, 162 insertions(+), 148 deletions(-) (limited to 'src') diff --git a/include/mruby/hash.h b/include/mruby/hash.h index dacdd9376..7811894ae 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -18,7 +18,7 @@ MRB_BEGIN_DECL struct RHash { MRB_OBJECT_HEADER; struct iv_tbl *iv; - struct seglist *ht; + struct htable *ht; }; #define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v))) diff --git a/src/hash.c b/src/hash.c index 376c054cb..f43fd901c 100644 --- a/src/hash.c +++ b/src/hash.c @@ -17,11 +17,12 @@ mrb_int mrb_float_id(mrb_float f); #endif /* return non zero to break the loop */ -typedef int (sg_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); +typedef int (ht_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); -#ifndef MRB_SG_SEGMENT_SIZE -#define MRB_SG_SEGMENT_SIZE 5 +#ifndef MRB_HT_INIT_SIZE +#define MRB_HT_INIT_SIZE 4 #endif +#define HT_SEG_INCREASE_RATIO 1.2 struct segkv { mrb_value key; @@ -29,8 +30,9 @@ struct segkv { }; typedef struct segment { + uint16_t size; struct segment *next; - struct segkv e[MRB_SG_SEGMENT_SIZE]; + struct segkv e[]; } segment; typedef struct segindex { @@ -40,16 +42,16 @@ typedef struct segindex { } segindex; /* Instance variable table structure */ -typedef struct seglist { +typedef struct htable { segment *rootseg; segment *lastseg; mrb_int size; - mrb_int last_len; + uint16_t last_len; segindex *index; -} seglist; +} htable; static /* inline */ size_t -sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key) +ht_hash_func(mrb_state *mrb, htable *t, mrb_value key) { enum mrb_vtype tt = mrb_type(key); mrb_value hv; @@ -84,7 +86,7 @@ sg_hash_func(mrb_state *mrb, seglist *t, mrb_value key) } static inline mrb_bool -sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b) +ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b) { enum mrb_vtype tt = mrb_type(a); @@ -134,12 +136,12 @@ sg_hash_equal(mrb_state *mrb, seglist *t, mrb_value a, mrb_value b) } /* Creates the instance variable table. */ -static seglist* -sg_new(mrb_state *mrb) +static htable* +ht_new(mrb_state *mrb) { - seglist *t; + htable *t; - t = (seglist*)mrb_malloc(mrb, sizeof(seglist)); + t = (htable*)mrb_malloc(mrb, sizeof(htable)); t->size = 0; t->rootseg = NULL; t->lastseg = NULL; @@ -163,11 +165,11 @@ sg_new(mrb_state *mrb) #define UPPER_BOUND(x) ((x)>>2|(x)>>1) #endif -#define SG_MASK(index) ((index->capa)-1) +#define HT_MASK(index) ((index->capa)-1) -/* Build index for the segment list */ +/* Build index for the hash table */ static void -sg_index(mrb_state *mrb, seglist *t) +ht_index(mrb_state *mrb, htable *t) { size_t size = (size_t)t->size; size_t mask; @@ -175,14 +177,6 @@ sg_index(mrb_state *mrb, seglist *t) segment *seg; size_t i; - if (size < MRB_SG_SEGMENT_SIZE) { - if (index) { - failed: - mrb_free(mrb, index); - t->index = NULL; - } - return; - } /* allocate index table */ if (index && index->size >= UPPER_BOUND(index->capa)) { size = index->capa+1; @@ -190,7 +184,11 @@ sg_index(mrb_state *mrb, seglist *t) power2(size); if (!index || index->capa < size) { index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); - if (index == NULL) goto failed; + if (index == NULL) { + mrb_free(mrb, index); + t->index = NULL; + return; + } t->index = index; } index->size = t->size; @@ -200,10 +198,10 @@ sg_index(mrb_state *mrb, seglist *t) } /* rebuld index */ - mask = SG_MASK(index); + mask = HT_MASK(index); seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { mrb_value key; size_t k, step = 0; @@ -212,7 +210,7 @@ sg_index(mrb_state *mrb, seglist *t) } key = seg->e[i].key; if (mrb_undef_p(key)) continue; - k = sg_hash_func(mrb, t, key) & mask; + k = ht_hash_func(mrb, t, key) & mask; while (index->table[k]) { k = (k+(++step)) & mask; } @@ -222,9 +220,9 @@ sg_index(mrb_state *mrb, seglist *t) } } -/* Compacts the segment list removing deleted entries. */ +/* Compacts the hash table removing deleted entries. */ static void -sg_compact(mrb_state *mrb, seglist *t) +ht_compact(mrb_state *mrb, htable *t) { segment *seg; mrb_int i; @@ -235,11 +233,11 @@ sg_compact(mrb_state *mrb, seglist *t) if (t == NULL) return; seg = t->rootseg; if (t->index && (size_t)t->size == t->index->size) { - sg_index(mrb, t); + ht_index(mrb, t); return; } while (seg) { - for (i=0; isize; i++) { mrb_value k = seg->e[i].key; if (!seg->next && i >= t->last_len) { @@ -255,7 +253,7 @@ sg_compact(mrb_state *mrb, seglist *t) size++; if (seg2 != NULL) { seg2->e[i2++] = seg->e[i]; - if (i2 >= MRB_SG_SEGMENT_SIZE) { + if (i2 >= seg2->size) { seg2 = seg2->next; i2 = 0; } @@ -279,13 +277,31 @@ sg_compact(mrb_state *mrb, seglist *t) } } if (t->index) { - sg_index(mrb, t); + ht_index(mrb, t); } } -/* Set the value for the key in the indexed segment list. */ +static segment* +segment_alloc(mrb_state *mrb, segment *seg) +{ + uint32_t size; + + if (!seg) size = MRB_HT_INIT_SIZE; + else { + size = seg->size*HT_SEG_INCREASE_RATIO + 1; + if (size > UINT16_MAX) size = UINT16_MAX; + } + + seg = (segment*)mrb_malloc(mrb, sizeof(segment)+sizeof(struct segkv)*size); + seg->size = size; + seg->next = NULL; + + return seg; +} + +/* Set the value for the key in the indexed table. */ static void -sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) { segindex *index = t->index; size_t k, sp, step = 0, mask; @@ -293,18 +309,18 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) if (index->size >= UPPER_BOUND(index->capa)) { /* need to expand table */ - sg_compact(mrb, t); + ht_compact(mrb, t); index = t->index; } - mask = SG_MASK(index); + mask = HT_MASK(index); sp = index->capa; - k = sg_hash_func(mrb, t, key) & mask; + k = ht_hash_func(mrb, t, key) & mask; while (index->table[k]) { mrb_value key2 = index->table[k]->key; if (mrb_undef_p(key2)) { if (sp == index->capa) sp = k; } - else if (sg_hash_equal(mrb, t, key, key2)) { + else if (ht_hash_equal(mrb, t, key, key2)) { index->table[k]->val = val; return; } @@ -316,11 +332,11 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) /* put the value at the last */ seg = t->lastseg; - if (t->last_len < MRB_SG_SEGMENT_SIZE) { + if (t->last_len < seg->size) { index->table[k] = &seg->e[t->last_len++]; } else { /* append a new segment */ - seg->next = (segment*)mrb_malloc(mrb, sizeof(segment)); + seg->next = segment_alloc(mrb, seg); seg = seg->next; seg->next = NULL; t->lastseg = seg; @@ -333,21 +349,21 @@ sg_index_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) t->size++; } -/* Set the value for the key in the segment list. */ +/* Set the value for the key in the table. */ static void -sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) +ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) { segment *seg; mrb_int i, deleted = 0; if (t == NULL) return; if (t->index) { - sg_index_put(mrb, t, key, val); + ht_index_put(mrb, t, key, val); return; } seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { mrb_value k = seg->e[i].key; /* Found room in last segment after last_len */ if (!seg->next && i >= t->last_len) { @@ -361,49 +377,58 @@ sg_put(mrb_state *mrb, seglist *t, mrb_value key, mrb_value val) deleted++; continue; } - if (sg_hash_equal(mrb, t, k, key)) { + if (ht_hash_equal(mrb, t, k, key)) { seg->e[i].val = val; return; } } seg = seg->next; } - /* Not found */ - if (deleted > MRB_SG_SEGMENT_SIZE) { - sg_compact(mrb, t); + + /* Compact if last segment has room */ + if (deleted > 0 && deleted > MRB_HT_INIT_SIZE) { + ht_compact(mrb, t); } t->size++; - seg = (segment*)mrb_malloc(mrb, sizeof(segment)); - seg->next = NULL; - seg->e[0].key = key; - seg->e[0].val = val; - t->last_len = 1; - if (t->rootseg == NULL) { - t->rootseg = seg; + /* check if thre's room after compaction */ + if (t->lastseg && t->last_len < t->lastseg->size) { + seg = t->lastseg; + i = t->last_len; } else { - t->lastseg->next = seg; + /* append new segment */ + seg = segment_alloc(mrb, t->lastseg); + i = 0; + if (t->rootseg == NULL) { + t->rootseg = seg; + } + else { + t->lastseg->next = seg; + } + t->lastseg = seg; } - t->lastseg = seg; - if (t->index == NULL && t->size > MRB_SG_SEGMENT_SIZE*4) { - sg_index(mrb, t); + seg->e[i].key = key; + seg->e[i].val = val; + t->last_len = i+1; + if (t->index == NULL && t->size > MRB_HT_INIT_SIZE*4) { + ht_index(mrb, t); } } -/* Get a value for a key from the indexed segment list. */ +/* Get a value for a key from the indexed table. */ static mrb_bool -sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +ht_index_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) { segindex *index = t->index; - size_t mask = SG_MASK(index); - size_t k = sg_hash_func(mrb, t, key) & mask; + size_t mask = HT_MASK(index); + size_t k = ht_hash_func(mrb, t, key) & mask; size_t step = 0; while (index->table[k]) { mrb_value key2 = index->table[k]->key; - if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { + if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) { if (vp) *vp = index->table[k]->val; return TRUE; } @@ -412,28 +437,28 @@ sg_index_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Get a value for a key from the segment list. */ +/* Get a value for a key from the hash table. */ static mrb_bool -sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) { segment *seg; mrb_int i; if (t == NULL) return FALSE; if (t->index) { - return sg_index_get(mrb, t, key, vp); + return ht_index_get(mrb, t, key, vp); } seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { mrb_value k = seg->e[i].key; if (!seg->next && i >= t->last_len) { return FALSE; } if (mrb_undef_p(k)) continue; - if (sg_hash_equal(mrb, t, k, key)) { + if (ht_hash_equal(mrb, t, k, key)) { if (vp) *vp = seg->e[i].val; return TRUE; } @@ -446,7 +471,7 @@ sg_get(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) /* Deletes the value for the symbol from the instance variable table. */ /* Deletion is done by overwriting keys by `undef`. */ static mrb_bool -sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) +ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) { segment *seg; mrb_int i; @@ -454,7 +479,7 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) if (t == NULL) return FALSE; seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { mrb_value key2; if (!seg->next && i >= t->last_len) { @@ -462,7 +487,7 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) return FALSE; } key2 = seg->e[i].key; - if (!mrb_undef_p(key2) && sg_hash_equal(mrb, t, key, key2)) { + if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) { if (vp) *vp = seg->e[i].val; seg->e[i].key = mrb_undef_value(); t->size--; @@ -476,18 +501,15 @@ sg_del(mrb_state *mrb, seglist *t, mrb_value key, mrb_value *vp) /* Iterates over the instance variable table. */ static void -sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) +ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) { segment *seg; mrb_int i; if (t == NULL) return; - if (t->index && t->index->size-(size_t)t->size > MRB_SG_SEGMENT_SIZE) { - sg_compact(mrb, t); - } seg = t->rootseg; while (seg) { - for (i=0; isize; i++) { /* no value in last segment after last_len */ if (!seg->next && i >= t->last_len) { return; @@ -500,34 +522,26 @@ sg_foreach(mrb_state *mrb, seglist *t, sg_foreach_func *func, void *p) } } -/* Get the size of the instance variable table. */ -static mrb_int -sg_size(mrb_state *mrb, seglist *t) -{ - if (t == NULL) return 0; - return t->size; -} - /* Copy the instance variable table. */ -static seglist* -sg_copy(mrb_state *mrb, seglist *t) +static htable* +ht_copy(mrb_state *mrb, htable *t) { segment *seg; - seglist *t2; + htable *t2; mrb_int i; seg = t->rootseg; - t2 = sg_new(mrb); + t2 = ht_new(mrb); - while (seg != NULL) { - for (i=0; isize; i++) { mrb_value key = seg->e[i].key; mrb_value val = seg->e[i].val; if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } - sg_put(mrb, t2, key, val); + ht_put(mrb, t2, key, val); } seg = seg->next; } @@ -536,7 +550,7 @@ sg_copy(mrb_state *mrb, seglist *t) /* Free memory of the instance variable table. */ static void -sg_free(mrb_state *mrb, seglist *t) +ht_free(mrb_state *mrb, htable *t) { segment *seg; @@ -576,20 +590,20 @@ hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) void mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash) { - sg_foreach(mrb, hash->ht, hash_mark_i, NULL); + ht_foreach(mrb, hash->ht, hash_mark_i, NULL); } size_t mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash) { if (!hash->ht) return 0; - return sg_size(mrb, hash->ht)*2; + return hash->ht->size*2; } void mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash) { - sg_free(mrb, hash->ht); + ht_free(mrb, hash->ht); } MRB_API mrb_value @@ -609,8 +623,8 @@ mrb_hash_new_capa(mrb_state *mrb, mrb_int capa) struct RHash *h; h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - /* preallocate segment list */ - h->ht = sg_new(mrb); + /* preallocate hash table */ + h->ht = ht_new(mrb); /* capacity ignored */ h->iv = 0; return mrb_obj_value(h); @@ -624,7 +638,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) { mrb_value orig; struct RHash* copy; - seglist *orig_h; + htable *orig_h; mrb_value ifnone, vret; mrb_get_args(mrb, "o", &orig); @@ -635,7 +649,7 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = sg_copy(mrb, orig_h); + copy->ht = ht_copy(mrb, orig_h); if (MRB_RHASH_DEFAULT_P(self)) { copy->flags |= MRB_HASH_DEFAULT; @@ -663,22 +677,22 @@ check_kdict_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self) { - seglist *sg; + htable *t; - sg = RHASH_TBL(self); - if (!sg || sg_size(mrb, sg) == 0) return; - sg_foreach(mrb, sg, check_kdict_i, NULL); + t = RHASH_TBL(self); + if (!t || t->size == 0) return; + ht_foreach(mrb, t, check_kdict_i, NULL); } MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value self) { struct RHash* copy; - seglist *orig_h; + htable *orig_h; orig_h = RHASH_TBL(self); copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); - copy->ht = orig_h ? sg_copy(mrb, orig_h) : NULL; + copy->ht = orig_h ? ht_copy(mrb, orig_h) : NULL; return mrb_obj_value(copy); } @@ -688,7 +702,7 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) mrb_value val; mrb_sym mid; - if (sg_get(mrb, RHASH_TBL(hash), key, &val)) { + if (ht_get(mrb, RHASH_TBL(hash), key, &val)) { return val; } @@ -705,7 +719,7 @@ mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def) { mrb_value val; - if (sg_get(mrb, RHASH_TBL(hash), key, &val)) { + if (ht_get(mrb, RHASH_TBL(hash), key, &val)) { return val; } /* not found */ @@ -718,7 +732,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) mrb_hash_modify(mrb, hash); key = KEY(key); - sg_put(mrb, RHASH_TBL(hash), key, val); + ht_put(mrb, RHASH_TBL(hash), key, val); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key); mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val); return; @@ -744,7 +758,7 @@ mrb_hash_modify(mrb_state *mrb, mrb_value hash) } if (!RHASH_TBL(hash)) { - RHASH_TBL(hash) = sg_new(mrb); + RHASH_TBL(hash) = ht_new(mrb); } } @@ -985,10 +999,10 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key) { - seglist *sg = RHASH_TBL(hash); + htable *t = RHASH_TBL(hash); mrb_value del_val; - if (sg_del(mrb, sg, key, &del_val)) { + if (ht_del(mrb, t, key, &del_val)) { return del_val; } @@ -1006,15 +1020,15 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } -/* find first element in segment list, and remove it. */ +/* find first element in a hash table, and remove it. */ static void -sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp) +ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp) { segment *seg = t->rootseg; mrb_int i; while (seg) { - for (i=0; isize; i++) { mrb_value key; if (!seg->next && i >= t->last_len) { @@ -1050,13 +1064,13 @@ sg_shift(mrb_state *mrb, seglist *t, mrb_value *kp, mrb_value *vp) static mrb_value mrb_hash_shift(mrb_state *mrb, mrb_value hash) { - seglist *sg = RHASH_TBL(hash); + htable *t = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (sg && sg_size(mrb, sg) > 0) { + if (t && t->size > 0) { mrb_value del_key, del_val; - sg_shift(mrb, sg, &del_key, &del_val); + ht_shift(mrb, t, &del_key, &del_val); mrb_gc_protect(mrb, del_key); mrb_gc_protect(mrb, del_val); return mrb_assoc_new(mrb, del_key, del_val); @@ -1088,11 +1102,11 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash) { - seglist *sg = RHASH_TBL(hash); + htable *t = RHASH_TBL(hash); mrb_hash_modify(mrb, hash); - if (sg) { - sg_free(mrb, sg); + if (t) { + ht_free(mrb, t); RHASH_TBL(hash) = NULL; } return hash; @@ -1144,19 +1158,19 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - seglist *sg = RHASH_TBL(self); + htable *t = RHASH_TBL(self); - if (!sg) return mrb_fixnum_value(0); - return mrb_fixnum_value(sg_size(mrb, sg)); + if (!t) return mrb_fixnum_value(0); + return mrb_fixnum_value(t->size); } MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self) { - seglist *sg = RHASH_TBL(self); + htable *t = RHASH_TBL(self); - if (!sg) return TRUE; - return sg_size(mrb, sg) == 0; + if (!t) return TRUE; + return t->size == 0; } /* 15.2.13.4.12 */ @@ -1212,14 +1226,14 @@ hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash) { - seglist *sg = RHASH_TBL(hash); - size_t size; + htable *t = RHASH_TBL(hash); + mrb_int size; mrb_value ary; - if (!sg || (size = sg_size(mrb, sg)) == 0) + if (!t || (size = t->size) == 0) return mrb_ary_new(mrb); ary = mrb_ary_new_capa(mrb, size); - sg_foreach(mrb, sg, hash_keys_i, (void*)&ary); + ht_foreach(mrb, t, hash_keys_i, (void*)&ary); return ary; } @@ -1246,14 +1260,14 @@ hash_vals_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash) { - seglist *sg = RHASH_TBL(hash); - size_t size; + htable *t = RHASH_TBL(hash); + mrb_int size; mrb_value ary; - if (!sg || (size = sg_size(mrb, sg)) == 0) + if (!t || (size = t->size) == 0) return mrb_ary_new(mrb); ary = mrb_ary_new_capa(mrb, size); - sg_foreach(mrb, sg, hash_vals_i, (void*)&ary); + ht_foreach(mrb, t, hash_vals_i, (void*)&ary); return ary; } @@ -1279,10 +1293,10 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key) { - seglist *sg; + htable *t; - sg = RHASH_TBL(hash); - if (sg_get(mrb, sg, key, NULL)) { + t = RHASH_TBL(hash); + if (ht_get(mrb, t, key, NULL)) { return TRUE; } return FALSE; @@ -1340,23 +1354,23 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash) mrb_get_args(mrb, "o", &val); arg.found = FALSE; arg.val = val; - sg_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg); + ht_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg); return mrb_bool_value(arg.found); } static int merge_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data) { - seglist *h1 = (seglist*)data; + htable *h1 = (htable*)data; - sg_put(mrb, h1, key, val); + ht_put(mrb, h1, key, val); return 0; } MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) { - seglist *h1, *h2; + htable *h1, *h2; mrb_hash_modify(mrb, hash1); hash2 = mrb_ensure_hash_type(mrb, hash2); @@ -1365,10 +1379,10 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) if (!h2) return; if (!h1) { - RHASH_TBL(hash1) = sg_copy(mrb, h2); + RHASH_TBL(hash1) = ht_copy(mrb, h2); return; } - sg_foreach(mrb, h2, merge_i, h1); + ht_foreach(mrb, h2, merge_i, h1); mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1)); return; } @@ -1389,7 +1403,7 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) static mrb_value mrb_hash_rehash(mrb_state *mrb, mrb_value self) { - sg_compact(mrb, RHASH_TBL(self)); + ht_compact(mrb, RHASH_TBL(self)); return self; } -- cgit v1.2.3 From cab6b0f39b77098425b1c3c80e8e1d193d5882c8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 09:49:20 +0900 Subject: Protect Fiber from GC in `ecall()`; fix #4104 --- src/vm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 2b88b0761..b899a2d70 100644 --- a/src/vm.c +++ b/src/vm.c @@ -364,6 +364,9 @@ ecall(mrb_state *mrb) if (exc) { mrb_gc_protect(mrb, mrb_obj_value(exc)); } + if (mrb->c->fib) { + mrb_gc_protect(mrb, mrb_obj_value(mrb->c->fib)); + } mrb_run(mrb, p, env->stack[0]); mrb->c = c; c->ci = c->cibase + cioff; -- cgit v1.2.3 From 31a961acf16b7a9454ccb0f0ece91b79e95f7078 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 09:50:31 +0900 Subject: The current context may be changed in `mrb_vm_exec`; ref #3668 #4104 --- src/vm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index b899a2d70..2d12df4ba 100644 --- a/src/vm.c +++ b/src/vm.c @@ -973,15 +973,15 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac stack_clear(c->stack + stack_keep, nregs - stack_keep); c->stack[0] = self; result = mrb_vm_exec(mrb, proc, irep->iseq); - if (c->ci - c->cibase > cioff) { - c->ci = c->cibase + cioff; - } if (mrb->c != c) { if (mrb->c->fib) { mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib); } mrb->c = c; } + else if (c->ci - c->cibase > cioff) { + c->ci = c->cibase + cioff; + } return result; } -- cgit v1.2.3 From afca99a40b8a3415b3a9a0e8fc41c93ddcbb11d8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 20:53:32 +0900 Subject: Remove implicit conversion using `to_int` method. The ISO standard does not include implicit type conversion using `to_int`. This implicit conversion often causes vulnerability. There will be no more attacks like #4120. In addition, we have added internal convenience method `__to_int` which does type check and conversion (from floats). --- include/mruby.h | 1 - mrbgems/mruby-enum-ext/mrblib/enum.rb | 27 +++++-------- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 8 ++-- mrbgems/mruby-enumerator/test/enumerator.rb | 6 --- mrbgems/mruby-kernel-ext/src/kernel.c | 5 +-- mrbgems/mruby-numeric-ext/src/numeric_ext.c | 17 ++++---- mrbgems/mruby-pack/src/pack.c | 6 ++- mrbgems/mruby-random/src/random.c | 12 +++--- mrbgems/mruby-random/test/random.rb | 12 ------ mrbgems/mruby-range-ext/mrblib/range.rb | 5 +-- mrbgems/mruby-string-ext/test/string.rb | 12 ------ mrblib/array.rb | 2 +- src/kernel.c | 2 + src/numeric.c | 4 -- src/object.c | 57 ++++++++------------------- 15 files changed, 51 insertions(+), 125 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 8eff31746..33597101a 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -716,7 +716,6 @@ MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value); * @return [mrb_value] The newly duplicated object. */ MRB_API mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj); -MRB_API mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method); /** * Returns true if obj responds to the given method. If the method was defined for that diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index ba92decee..fedf8b1ae 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -13,10 +13,9 @@ module Enumerable # a.drop(3) #=> [4, 5, 0] def drop(n) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "attempt to drop negative size" if n < 0 - n = n.to_int ary = [] self.each {|*val| n == 0 ? ary << val.__svalue : n -= 1 } ary @@ -57,8 +56,8 @@ module Enumerable # a.take(3) #=> [1, 2, 3] def take(n) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) - i = n.to_int + n = n.__to_int + i = n.to_i raise ArgumentError, "attempt to take negative size" if i < 0 ary = [] return ary if i == 0 @@ -113,12 +112,12 @@ module Enumerable # [8, 9, 10] def each_cons(n, &block) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "invalid size" if n <= 0 return to_enum(:each_cons,n) unless block ary = [] - n = n.to_int + n = n.to_i self.each do |*val| ary.shift if ary.size == n ary << val.__svalue @@ -141,12 +140,12 @@ module Enumerable # [10] def each_slice(n, &block) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "invalid slice size" if n <= 0 return to_enum(:each_slice,n) unless block ary = [] - n = n.to_int + n = n.to_i self.each do |*val| ary << val.__svalue if ary.size == n @@ -223,9 +222,7 @@ module Enumerable end return nil when 1 - n = args[0] - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) - i = n.to_int + i = args[0].__to_int raise ArgumentError, "attempt to take negative size" if i < 0 ary = [] return ary if i == 0 @@ -673,13 +670,7 @@ module Enumerable if nv.nil? n = -1 else - unless nv.respond_to?(:to_int) - raise TypeError, "no implicit conversion of #{nv.class} into Integer" - end - n = nv.to_int - unless n.kind_of?(Integer) - raise TypeError, "no implicit conversion of #{nv.class} into Integer" - end + n = nv.__to_int return nil if n <= 0 end diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index dbc7d3004..6dd971f3a 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -157,12 +157,10 @@ class Enumerator def with_index(offset=0, &block) return to_enum :with_index, offset unless block - offset = if offset.nil? - 0 - elsif offset.respond_to?(:to_int) - offset.to_int + if offset.nil? + offset = 0 else - raise TypeError, "no implicit conversion of #{offset.class} into Integer" + offset = offset.__to_int end n = offset - 1 diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index ef4970883..f3bd1bdba 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -54,12 +54,6 @@ assert 'Enumerator#with_index' do assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a end -assert 'Enumerator#with_index nonnum offset' do - s = Object.new - def s.to_int; 1 end - assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a) -end - assert 'Enumerator#with_index string offset' do assert_raise(TypeError){ @obj.to_enum(:foo, 1, 2, 3).with_index('1').to_a } end diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 32d86376a..a60e9a210 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -93,9 +93,8 @@ mrb_f_method(mrb_state *mrb, mrb_value self) * (0, 0b, and 0x) are honored. * In any case, strings should be strictly conformed to numeric * representation. This behavior is different from that of - * String#to_i. Non string values will be converted using - * to_int, and to_i. Passing nil - * raises a TypeError. + * String#to_i. Non string values will be treated as integers. + * Passing nil raises a TypeError. * * Integer(123.999) #=> 123 * Integer("0x1a") #=> 26 diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index 1d6a07769..cd8bbf187 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -2,13 +2,10 @@ #include static inline mrb_int -to_int(mrb_value x) +to_int(mrb_state *mrb, mrb_value x) { - double f; - - if (mrb_fixnum_p(x)) return mrb_fixnum(x); - f = mrb_float(x); - return (mrb_int)f; + x = mrb_to_int(mrb, x); + return mrb_fixnum(x); } /* @@ -28,7 +25,7 @@ mrb_int_chr(mrb_state *mrb, mrb_value x) mrb_int chr; char c; - chr = to_int(x); + chr = to_int(mrb, x); if (chr >= (1 << CHAR_BIT)) { mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", x); } @@ -48,8 +45,8 @@ mrb_int_allbits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) == m); } @@ -64,8 +61,8 @@ mrb_int_anybits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) != 0); } @@ -80,8 +77,8 @@ mrb_int_nobits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) == 0); } diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 796ba4d34..5caf7b62b 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1124,14 +1124,16 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) o = mrb_ary_ref(mrb, ary, aidx); if (type == PACK_TYPE_INTEGER) { o = mrb_to_int(mrb, o); + } #ifndef MRB_WITHOUT_FLOAT - } else if (type == PACK_TYPE_FLOAT) { + else if (type == PACK_TYPE_FLOAT) { if (!mrb_float_p(o)) { mrb_float f = mrb_to_flo(mrb, o); o = mrb_float_value(mrb, f); } + } #endif - } else if (type == PACK_TYPE_STRING) { + else if (type == PACK_TYPE_STRING) { if (!mrb_string_p(o)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o))); } diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index 5b926a228..68209840a 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -79,12 +79,12 @@ get_opt(mrb_state* mrb) mrb_get_args(mrb, "|o", &arg); if (!mrb_nil_p(arg)) { - arg = mrb_check_convert_type(mrb, arg, MRB_TT_FIXNUM, "Fixnum", "to_int"); - if (mrb_nil_p(arg)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type"); - } - if (mrb_fixnum(arg) < 0) { - arg = mrb_fixnum_value(0 - mrb_fixnum(arg)); + mrb_int i; + + arg = mrb_to_int(mrb, arg); + i = mrb_fixnum(arg); + if (i < 0) { + arg = mrb_fixnum_value(0 - i); } } return arg; diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb index 1c59be3a6..1653ae4a6 100644 --- a/mrbgems/mruby-random/test/random.rb +++ b/mrbgems/mruby-random/test/random.rb @@ -74,15 +74,3 @@ assert('Array#shuffle!(random)') do ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2 end - -assert('Array#sample checks input length after reading arguments') do - $ary = [1, 2, 3] - class ArrayChange - def to_i - $ary << 4 - 4 - end - end - - assert_equal [1, 2, 3, 4], $ary.sample(ArrayChange.new).sort -end diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index e5d1fb079..de7925ba7 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -15,10 +15,7 @@ class Range raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1)" unless args.length == 1 nv = args[0] - raise TypeError, "no implicit conversion from nil to integer" if nv.nil? - raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless nv.respond_to?(:to_int) - n = nv.to_int - raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless n.kind_of?(Integer) + n = nv.__to_int raise ArgumentError, "negative array size (or size too big)" unless 0 <= n ary = [] each do |i| diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index f0f8be6b3..781506949 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -31,18 +31,6 @@ assert('String#setbyte') do assert_equal("Hello", str1) end -assert("String#setbyte raises IndexError if arg conversion resizes String") do - $s = "01234\n" - class Tmp - def to_i - $s.chomp! '' - 95 - end - end - tmp = Tmp.new - assert_raise(IndexError) { $s.setbyte(5, tmp) } -end - assert('String#byteslice') do str1 = "hello" assert_equal("e", str1.byteslice(1)) diff --git a/mrblib/array.rb b/mrblib/array.rb index 53d880660..a677b2a1f 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -66,7 +66,7 @@ class Array # # ISO 15.2.12.5.15 def initialize(size=0, obj=nil, &block) - raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integral + size = size.__to_int raise ArgumentError, "negative array size" if size < 0 self.clear diff --git a/src/kernel.c b/src/kernel.c index db681d510..195594d6b 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -830,6 +830,7 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) } mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); + void mrb_init_kernel(mrb_state *mrb) { @@ -871,6 +872,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ + mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); diff --git a/src/numeric.c b/src/numeric.c index f7f0318e8..3624831cc 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -674,7 +674,6 @@ flo_round(mrb_state *mrb, mrb_value num) /* * call-seq: * flt.to_i -> integer - * flt.to_int -> integer * flt.truncate -> integer * * Returns flt truncated to an Integer. @@ -714,7 +713,6 @@ flo_nan_p(mrb_state *mrb, mrb_value num) /* * call-seq: * int.to_i -> integer - * int.to_int -> integer * * As int is already an Integer, all these * methods simply return the receiver. @@ -1513,7 +1511,6 @@ mrb_init_numeric(mrb_state *mrb) MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM); mrb_undef_class_method(mrb, integer, "new"); mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ - mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ @@ -1565,7 +1562,6 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ - mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ diff --git a/src/object.c b/src/object.c index 8724c5416..ba6fa3947 100644 --- a/src/object.c +++ b/src/object.c @@ -322,19 +322,6 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho return mrb_funcall_argv(mrb, val, m, 0, 0); } -MRB_API mrb_value -mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, FALSE); - if (mrb_nil_p(v) || !mrb_fixnum_p(v)) { - return mrb_nil_value(); - } - return v; -} - MRB_API mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) { @@ -505,25 +492,22 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) return FALSE; } -static mrb_value -mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, TRUE); - if (!mrb_obj_is_kind_of(mrb, v, mrb->fixnum_class)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer (%S#%S gives %S)", - type, type, mrb_str_new_cstr(mrb, method), inspect_type(mrb, v)); - } - return v; -} - MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val) { - return mrb_to_integer(mrb, val, "to_int"); + + if (!mrb_fixnum_p(val)) { + mrb_value type; + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(val)) { + return mrb_flo_to_fixnum(mrb, val); + } +#endif + type = inspect_type(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer", type); + } + return val; } MRB_API mrb_value @@ -533,18 +517,12 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) if (mrb_nil_p(val)) { if (base != 0) goto arg_error; - mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); + mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); } switch (mrb_type(val)) { #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: if (base != 0) goto arg_error; - else { - mrb_float f = mrb_float(val); - if (FIXABLE_FLOAT(f)) { - break; - } - } return mrb_flo_to_fixnum(mrb, val); #endif @@ -568,11 +546,8 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) arg_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); } - tmp = convert_type(mrb, val, "Integer", "to_int", FALSE); - if (mrb_nil_p(tmp) || !mrb_fixnum_p(tmp)) { - tmp = mrb_to_integer(mrb, val, "to_i"); - } - return tmp; + /* to raise TypeError */ + return mrb_to_int(mrb, val); } MRB_API mrb_value -- cgit v1.2.3 From ff08856fe314faa4d16b4502c0960a3475387846 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 21:51:53 +0900 Subject: Remove implicit conversion using `to_str` method; fix #3854 We have added internal convenience method `__to_str` which does string type check. The issue #3854 was fixed but fundamental flaw of lack of stack depth check along with fibers still remains. Use `MRB_GC_FIXED_ARENA` for workaround. --- include/mruby.h | 5 +--- include/mruby/string.h | 3 +-- mrbgems/mruby-io/src/file.c | 2 +- mrbgems/mruby-kernel-ext/src/kernel.c | 8 ++----- mrbgems/mruby-string-ext/mrblib/string.rb | 6 ++--- mrbgems/mruby-string-ext/src/string.c | 6 ++--- mrbgems/mruby-string-ext/test/string.rb | 11 --------- mrblib/string.rb | 11 ++++----- src/class.c | 11 +++++++-- src/kernel.c | 39 +++++-------------------------- src/object.c | 27 +++++++++++++++++++++ src/string.c | 32 ++----------------------- test/t/string.rb | 13 ----------- 13 files changed, 60 insertions(+), 114 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 33597101a..12df9cd5a 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -854,10 +854,6 @@ typedef const char *mrb_args_format; /** * Retrieve arguments from mrb_state. * - * When applicable, implicit conversions (such as `to_str`, `to_ary`, `to_hash`) are - * applied to received arguments. - * Used inside a function of mrb_func_t type. - * * @param mrb The current MRuby state. * @param format [mrb_args_format] is a list of format specifiers * @param ... The passing variadic arguments must be a pointer of retrieving type. @@ -1187,6 +1183,7 @@ MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj); MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); #define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, val)) +MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); typedef enum call_type { diff --git a/include/mruby/string.h b/include/mruby/string.h index 481b2fb38..fa1955f48 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -311,8 +311,7 @@ MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb * @param [mrb_value] str Ruby string. * @return [mrb_value] A Ruby string. */ -MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); - +MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa); MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index e65741061..c00663481 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -115,7 +115,7 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) mrb_get_args(mrb, "*", &argv, &argc); for (i = 0; i < argc; i++) { const char *utf8_path; - pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str"); + pathv = mrb_ensure_string_type(mrb, argv[i]); utf8_path = mrb_string_value_cstr(mrb, &pathv); path = mrb_locale_from_utf8(utf8_path, -1); if (UNLINK(path) < 0) { diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index a60e9a210..bc2656399 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -141,8 +141,7 @@ mrb_f_float(mrb_state *mrb, mrb_value self) * String(arg) -> string * * Returns arg as an String. - * - * First tries to call its to_str method, then its to_s method. + * converted using to_s method. * * String(self) #=> "main" * String(self.class) #=> "Object" @@ -154,10 +153,7 @@ mrb_f_string(mrb_state *mrb, mrb_value self) mrb_value arg, tmp; mrb_get_args(mrb, "o", &arg); - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_str"); - if (mrb_nil_p(tmp)) { - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s"); - } + tmp = mrb_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s"); return tmp; } diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 27ca30610..9212d83a5 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -12,8 +12,8 @@ class String # String.try_convert(/re/) #=> nil # def self.try_convert(obj) - if obj.respond_to?(:to_str) - obj.to_str + if self === obj + obj else nil end @@ -142,7 +142,7 @@ class String # "abcdef".casecmp("ABCDEF") #=> 0 # def casecmp(str) - self.downcase <=> str.to_str.downcase + self.downcase <=> str.__to_str.downcase rescue NoMethodError nil end diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 6d661c352..ba7e3c610 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -163,7 +163,7 @@ mrb_str_concat_m(mrb_state *mrb, mrb_value self) if (mrb_fixnum_p(str)) str = mrb_fixnum_chr(mrb, str); else - str = mrb_string_type(mrb, str); + str = mrb_ensure_string_type(mrb, str); mrb_str_concat(mrb, self, str); return self; } @@ -191,7 +191,7 @@ mrb_str_start_with(mrb_state *mrb, mrb_value self) for (i = 0; i < argc; i++) { size_t len_l, len_r; int ai = mrb_gc_arena_save(mrb); - sub = mrb_string_type(mrb, argv[i]); + sub = mrb_ensure_string_type(mrb, argv[i]); mrb_gc_arena_restore(mrb, ai); len_l = RSTRING_LEN(self); len_r = RSTRING_LEN(sub); @@ -220,7 +220,7 @@ mrb_str_end_with(mrb_state *mrb, mrb_value self) for (i = 0; i < argc; i++) { size_t len_l, len_r; int ai = mrb_gc_arena_save(mrb); - sub = mrb_string_type(mrb, argv[i]); + sub = mrb_ensure_string_type(mrb, argv[i]); mrb_gc_arena_restore(mrb, ai); len_l = RSTRING_LEN(self); len_r = RSTRING_LEN(sub); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 781506949..4ccdfd6c3 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -114,12 +114,6 @@ assert('String#concat') do assert_equal "Hello World!", "Hello " << "World" << 33 assert_equal "Hello World!", "Hello ".concat("World").concat(33) - o = Object.new - def o.to_str - "to_str" - end - assert_equal "hi to_str", "hi " << o - assert_raise(TypeError) { "".concat(Object.new) } end @@ -128,11 +122,6 @@ assert('String#casecmp') do assert_equal 0, "aBcDeF".casecmp("abcdef") assert_equal(-1, "abcdef".casecmp("abcdefg")) assert_equal 0, "abcdef".casecmp("ABCDEF") - o = Object.new - def o.to_str - "ABCDEF" - end - assert_equal 0, "abcdef".casecmp(o) end assert('String#count') do diff --git a/mrblib/string.rb b/mrblib/string.rb index 07b80b340..397603e9d 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -12,7 +12,7 @@ class String def each_line(rs = "\n", &block) return to_enum(:each_line, rs, &block) unless block return block.call(self) if rs.nil? - rs = rs.to_str + rs = rs.__to_str offset = 0 rs_len = rs.length this = dup @@ -67,7 +67,7 @@ class String block = nil end if !replace.nil? || !block - replace = replace.to_str + replace = replace.__to_str end offset = 0 result = [] @@ -129,12 +129,12 @@ class String end pattern, replace = *args - pattern = pattern.to_str + pattern = pattern.__to_str if args.length == 2 && block block = nil end unless block - replace = replace.to_str + replace = replace.__to_str end result = [] this = dup @@ -245,14 +245,13 @@ class String ## # ISO 15.2.10.5.3 def =~(re) - raise TypeError, "type mismatch: String given" if re.respond_to? :to_str re =~ self end ## # ISO 15.2.10.5.27 def match(re, &block) - if re.respond_to? :to_str + if String === re if Object.const_defined?(:Regexp) r = Regexp.new(re) r.match(self, &block) diff --git a/src/class.c b/src/class.c index 50ab0ea59..90c73104e 100644 --- a/src/class.c +++ b/src/class.c @@ -504,10 +504,17 @@ check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const return tmp; } +#define CHECK_TYPE(mrb, val, t, c) do { \ + if (mrb_type(val) != (t)) {\ + mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ + }\ +} while (0) + static mrb_value to_str(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_STRING, "String", "to_str"); + CHECK_TYPE(mrb, val, MRB_TT_STRING, "String"); + return val; } static mrb_value @@ -1972,7 +1979,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) } /* const get with class path string */ - path = mrb_string_type(mrb, path); + path = mrb_ensure_string_type(mrb, path); ptr = RSTRING_PTR(path); len = RSTRING_LEN(path); off = 0; diff --git a/src/kernel.c b/src/kernel.c index 195594d6b..ce9cd1d44 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -746,6 +746,7 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) { return mrb_respond_to(mrb, obj, id); } + /* 15.3.1.3.43 */ /* * call-seq: @@ -765,45 +766,16 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) static mrb_value obj_respond_to(mrb_state *mrb, mrb_value self) { - mrb_value mid; mrb_sym id, rtm_id; - mrb_bool priv = FALSE, respond_to_p = TRUE; - - mrb_get_args(mrb, "o|b", &mid, &priv); - - if (mrb_symbol_p(mid)) { - id = mrb_symbol(mid); - } - else { - mrb_value tmp; - if (mrb_string_p(mid)) { - tmp = mrb_check_intern_str(mrb, mid); - } - else { - tmp = mrb_check_string_type(mrb, mid); - if (mrb_nil_p(tmp)) { - tmp = mrb_inspect(mrb, mid); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); - } - tmp = mrb_check_intern_str(mrb, tmp); - } - if (mrb_nil_p(tmp)) { - respond_to_p = FALSE; - } - else { - id = mrb_symbol(tmp); - } - } - - if (respond_to_p) { - respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); - } + mrb_bool priv = FALSE, respond_to_p; + mrb_get_args(mrb, "n|b", &id, &priv); + respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); if (!respond_to_p) { rtm_id = mrb_intern_lit(mrb, "respond_to_missing?"); if (basic_obj_respond_to(mrb, self, rtm_id, !priv)) { mrb_value args[2], v; - args[0] = mid; + args[0] = mrb_symbol_value(id); args[1] = mrb_bool_value(priv); v = mrb_funcall_argv(mrb, self, rtm_id, 2, args); return mrb_bool_value(mrb_bool(v)); @@ -873,6 +845,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ + mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); diff --git a/src/object.c b/src/object.c index ba6fa3947..18ccacfb9 100644 --- a/src/object.c +++ b/src/object.c @@ -579,6 +579,33 @@ mrb_Float(mrb_state *mrb, mrb_value val) } #endif +MRB_API mrb_value +mrb_to_str(mrb_state *mrb, mrb_value val) +{ + if (!mrb_string_p(val)) { + mrb_value type = inspect_type(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to String", type); + } + return val; +} + +MRB_API mrb_value +mrb_ensure_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to String", + inspect_type(mrb, str)); + } + return str; +} + +MRB_API mrb_value +mrb_check_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) return mrb_nil_value(); + return str; +} + MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { diff --git a/src/string.c b/src/string.c index b7abfb762..b6d4ecef0 100644 --- a/src/string.c +++ b/src/string.c @@ -956,15 +956,7 @@ str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2) MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2) { - if (mrb_immediate_p(str2)) return FALSE; - if (!mrb_string_p(str2)) { - if (mrb_nil_p(str2)) return FALSE; - if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_str"))) { - return FALSE; - } - str2 = mrb_funcall(mrb, str2, "to_str", 0); - return mrb_equal(mrb, str2, str1); - } + if (!mrb_string_p(str2)) return FALSE; return str_eql(mrb, str1, str2); } @@ -992,14 +984,8 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1) MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str) { - mrb_value s; - if (!mrb_string_p(str)) { - s = mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); - if (mrb_nil_p(s)) { - s = mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); - } - return s; + return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); } return str; } @@ -1714,18 +1700,6 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } -MRB_API mrb_value -mrb_string_type(mrb_state *mrb, mrb_value str) -{ - return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); -} - -MRB_API mrb_value -mrb_check_string_type(mrb_state *mrb, mrb_value str) -{ - return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); -} - /* 15.2.10.5.30 */ /* * call-seq: @@ -2379,7 +2353,6 @@ mrb_str_to_f(mrb_state *mrb, mrb_value self) /* * call-seq: * str.to_s => str - * str.to_str => str * * Returns the receiver. */ @@ -2783,7 +2756,6 @@ mrb_init_string(mrb_state *mrb) #endif mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */ mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ - mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ diff --git a/test/t/string.rb b/test/t/string.rb index e91b915fe..3a1eced16 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -253,19 +253,6 @@ assert('String#chomp!', '15.2.10.5.10') do assert_equal 'abc', e end -assert('String#chomp! uses the correct length') do - class A - def to_str - $s.replace("AA") - "A" - end - end - - $s = "AAA" - $s.chomp!(A.new) - assert_equal $s, "A" -end - assert('String#chop', '15.2.10.5.11') do a = ''.chop b = 'abc'.chop -- cgit v1.2.3 From 698f5f707c2db334a15c605bf1b0d0cff42b1224 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 22:19:55 +0900 Subject: Removed `to_ary` conversion method. --- include/mruby/array.h | 1 + mrbgems/mruby-array-ext/mrblib/array.rb | 10 ---------- mrbgems/mruby-array-ext/test/array.rb | 16 ---------------- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 4 +--- mrbgems/mruby-kernel-ext/src/kernel.c | 9 ++------- src/array.c | 27 +++++---------------------- src/class.c | 3 ++- src/object.c | 17 +++++++++++++++++ 8 files changed, 28 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/include/mruby/array.h b/include/mruby/array.h index 6fffe4512..2457f68f2 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -199,6 +199,7 @@ MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val * @param other The array to replace it with. */ MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other); +MRB_API mrb_value mrb_ensure_array_type(mrb_state *mrb, mrb_value self); MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self); /* diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 54d62e3fd..bb95d70c5 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -772,16 +772,6 @@ class Array nil end - ## - # call-seq: - # ary.to_ary -> ary - # - # Returns +self+. - # - def to_ary - self - end - ## # call-seq: # ary.dig(idx, ...) -> object diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index b7467724c..853554bcc 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -331,27 +331,11 @@ assert('Array#to_h') do assert_raise(ArgumentError) { [[1]].to_h } end -assert('Array#to_h (Modified)') do - class A - def to_ary - $a.clear - nil - end - end - $a = [A.new] - assert_raise(TypeError) { $a.to_h } -end - assert("Array#index (block)") do assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } end -assert("Array#to_ary") do - assert_equal [], [].to_ary - assert_equal [1,2,3], [1,2,3].to_ary -end - assert("Array#dig") do h = [[[1]], 0] assert_equal(1, h.dig(0, 0, 0)) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 6dd971f3a..9d80bc552 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -624,9 +624,7 @@ module Enumerable # use Enumerator to use infinite sequence def zip(*args, &block) args = args.map do |a| - if a.respond_to?(:to_ary) - a.to_ary.to_enum(:each) - elsif a.respond_to?(:each) + if a.respond_to?(:each) a.to_enum(:each) else raise TypeError, "wrong argument type #{a.class} (must respond to :each)" diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index bc2656399..324753f6e 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -161,9 +161,7 @@ mrb_f_string(mrb_state *mrb, mrb_value self) * call-seq: * Array(arg) -> array * - * Returns +arg+ as an Array. - * - * First tries to call Array#to_ary on +arg+, then Array#to_a. + * Returns +arg+ as an Array using to_a method. * * Array(1..5) #=> [1, 2, 3, 4, 5] * @@ -174,10 +172,7 @@ mrb_f_array(mrb_state *mrb, mrb_value self) mrb_value arg, tmp; mrb_get_args(mrb, "o", &arg); - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_ary"); - if (mrb_nil_p(tmp)) { - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a"); - } + tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a"); if (mrb_nil_p(tmp)) { return mrb_ary_new_from_values(mrb, 1, &arg); } diff --git a/src/array.c b/src/array.c index eddd9b2ac..084b48dc0 100644 --- a/src/array.c +++ b/src/array.c @@ -1058,7 +1058,7 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) MRB_API mrb_value mrb_ary_splat(mrb_state *mrb, mrb_value v) { - mrb_value a, recv_class; + mrb_value a; if (mrb_array_p(v)) { return v; @@ -1069,22 +1069,11 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v) } a = mrb_funcall(mrb, v, "to_a", 0); - if (mrb_array_p(a)) { - return a; - } - else if (mrb_nil_p(a)) { + if (mrb_nil_p(a)) { return mrb_ary_new_from_values(mrb, 1, &v); } - else { - recv_class = mrb_obj_value(mrb_obj_class(mrb, v)); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Array (%S#to_a gives %S)", - recv_class, - recv_class, - mrb_obj_value(mrb_obj_class(mrb, a)) - ); - /* not reached */ - return mrb_undef_value(); - } + mrb_ensure_array_type(mrb, a); + return a; } static mrb_value @@ -1122,12 +1111,6 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(ARY_LEN(a) == 0); } -MRB_API mrb_value -mrb_check_array_type(mrb_state *mrb, mrb_value ary) -{ - return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary"); -} - MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset) { @@ -1181,7 +1164,7 @@ join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list) val = tmp; goto str_join; } - tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + tmp = mrb_check_array_type(mrb, val); if (!mrb_nil_p(tmp)) { val = tmp; goto ary_join; diff --git a/src/class.c b/src/class.c index 90c73104e..5d6ff4b39 100644 --- a/src/class.c +++ b/src/class.c @@ -520,7 +520,8 @@ to_str(mrb_state *mrb, mrb_value val) static mrb_value to_ary(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + CHECK_TYPE(mrb, val, MRB_TT_ARRAY, "Array"); + return val; } static mrb_value diff --git a/src/object.c b/src/object.c index 18ccacfb9..a105c62f0 100644 --- a/src/object.c +++ b/src/object.c @@ -606,6 +606,23 @@ mrb_check_string_type(mrb_state *mrb, mrb_value str) return str; } +MRB_API mrb_value +mrb_ensure_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Array", + inspect_type(mrb, ary)); + } + return ary; +} + +MRB_API mrb_value +mrb_check_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) return mrb_nil_value(); + return ary; +} + MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { -- cgit v1.2.3 From 610bcc88c2b4f3ca9bbfebb57279c25806fa0461 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 22:53:48 +0900 Subject: Removed `to_hash` conversion method. --- mrbgems/mruby-hash-ext/mrblib/hash.rb | 30 +++++++----------------------- mrbgems/mruby-kernel-ext/src/kernel.c | 20 ++++++-------------- mrbgems/mruby-sprintf/src/sprintf.c | 2 +- mrblib/hash.rb | 14 ++++---------- src/class.c | 15 ++------------- src/hash.c | 28 ---------------------------- src/object.c | 17 +++++++++++++++++ 7 files changed, 37 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb index f1143e25b..547f3404a 100644 --- a/mrbgems/mruby-hash-ext/mrblib/hash.rb +++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb @@ -27,9 +27,9 @@ class Hash length = object.length if length == 1 o = object[0] - if o.respond_to?(:to_hash) + if Hash === o h = self.new - object[0].to_hash.each { |k, v| h[k] = v } + o.each { |k, v| h[k] = v } return h elsif o.respond_to?(:to_a) h = self.new @@ -82,7 +82,7 @@ class Hash # def merge!(other, &block) - raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash) + raise TypeError, "Hash required (#{other.class} given)" unless Hash === other if block other.each_key{|k| self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k] @@ -310,11 +310,7 @@ class Hash # h1 < h1 #=> false # def <(hash) - begin - hash = hash.to_hash - rescue NoMethodError - raise TypeError, "can't convert #{hash.class} to Hash" - end + raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash size < hash.size and all? {|key, val| hash.key?(key) and hash[key] == val } @@ -334,11 +330,7 @@ class Hash # h1 <= h1 #=> true # def <=(hash) - begin - hash = hash.to_hash - rescue NoMethodError - raise TypeError, "can't convert #{hash.class} to Hash" - end + raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash size <= hash.size and all? {|key, val| hash.key?(key) and hash[key] == val } @@ -358,11 +350,7 @@ class Hash # h1 > h1 #=> false # def >(hash) - begin - hash = hash.to_hash - rescue NoMethodError - raise TypeError, "can't convert #{hash.class} to Hash" - end + raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash size > hash.size and hash.all? {|key, val| key?(key) and self[key] == val } @@ -382,11 +370,7 @@ class Hash # h1 >= h1 #=> true # def >=(hash) - begin - hash = hash.to_hash - rescue NoMethodError - raise TypeError, "can't convert #{hash.class} to Hash" - end + raise TypeError, "can't convert #{hash.class} to Hash" unless Hash === hash size >= hash.size and hash.all? {|key, val| key?(key) and self[key] == val } diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 324753f6e..99affbfa4 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -184,9 +184,9 @@ mrb_f_array(mrb_state *mrb, mrb_value self) * call-seq: * Hash(arg) -> hash * - * Converts arg to a Hash by calling - * arg.to_hash. Returns an empty Hash when - * arg is nil or []. + * Returns a Hash if arg is a Hash. + * Returns an empty Hash when arg is nil + * or []. * * Hash([]) #=> {} * Hash(nil) #=> {} @@ -197,21 +197,13 @@ mrb_f_array(mrb_state *mrb, mrb_value self) static mrb_value mrb_f_hash(mrb_state *mrb, mrb_value self) { - mrb_value arg, tmp; + mrb_value arg; mrb_get_args(mrb, "o", &arg); - if (mrb_nil_p(arg)) { + if (mrb_nil_p(arg) || (mrb_array_p(arg) && RARRAY_LEN(arg) == 0)) { return mrb_hash_new(mrb); } - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_HASH, "Hash", "to_hash"); - if (mrb_nil_p(tmp)) { - if (mrb_array_p(arg) && RARRAY_LEN(arg) == 0) { - return mrb_hash_new(mrb); - } - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into Hash", - mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, arg))); - } - return tmp; + return mrb_ensure_hash_type(mrb, arg); } /* diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 15d7b5464..5a4a7899e 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -233,7 +233,7 @@ get_hash(mrb_state *mrb, mrb_value *hash, mrb_int argc, const mrb_value *argv) if (argc != 2) { mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required"); } - tmp = mrb_check_convert_type(mrb, argv[1], MRB_TT_HASH, "Hash", "to_hash"); + tmp = mrb_check_hash_type(mrb, argv[1]); if (mrb_nil_p(tmp)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required"); } diff --git a/mrblib/hash.rb b/mrblib/hash.rb index 6b61218ff..609883ecb 100644 --- a/mrblib/hash.rb +++ b/mrblib/hash.rb @@ -12,9 +12,7 @@ class Hash # ISO 15.2.13.4.1 def ==(hash) return true if self.equal?(hash) - begin - hash = hash.to_hash - rescue NoMethodError + unless Hash === hash return false end return false if self.size != hash.size @@ -32,9 +30,7 @@ class Hash # ISO 15.2.13.4.32 (x) def eql?(hash) return true if self.equal?(hash) - begin - hash = hash.to_hash - rescue NoMethodError + unless Hash === hash return false end return false if self.size != hash.size @@ -153,9 +149,8 @@ class Hash # # ISO 15.2.13.4.23 def replace(hash) - raise TypeError, "can't convert argument into Hash" unless hash.respond_to?(:to_hash) + raise TypeError, "Hash required (#{hash.class} given)" unless Hash === hash self.clear - hash = hash.to_hash hash.each_key{|k| self[k] = hash[k] } @@ -178,8 +173,7 @@ class Hash # # ISO 15.2.13.4.22 def merge(other, &block) - raise TypeError, "can't convert argument into Hash" unless other.respond_to?(:to_hash) - other = other.to_hash + raise TypeError, "Hash required (#{other.class} given)" unless Hash === other h = self.dup if block other.each_key{|k| diff --git a/src/class.c b/src/class.c index 5d6ff4b39..dd5b65cc3 100644 --- a/src/class.c +++ b/src/class.c @@ -492,18 +492,6 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } -static mrb_value -check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m) -{ - mrb_value tmp; - - tmp = mrb_check_convert_type(mrb, val, t, c, m); - if (mrb_nil_p(tmp)) { - mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_cstr(mrb, c)); - } - return tmp; -} - #define CHECK_TYPE(mrb, val, t, c) do { \ if (mrb_type(val) != (t)) {\ mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ @@ -527,7 +515,8 @@ to_ary(mrb_state *mrb, mrb_value val) static mrb_value to_hash(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash"); + CHECK_TYPE(mrb, val, MRB_TT_HASH, "Hash"); + return val; } #define to_sym(mrb, ss) mrb_obj_to_sym(mrb, ss) diff --git a/src/hash.c b/src/hash.c index f43fd901c..467b20a51 100644 --- a/src/hash.c +++ b/src/hash.c @@ -738,18 +738,6 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) return; } -MRB_API mrb_value -mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) -{ - return mrb_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); -} - -MRB_API mrb_value -mrb_check_hash_type(mrb_state *mrb, mrb_value hash) -{ - return mrb_check_convert_type(mrb, hash, MRB_TT_HASH, "Hash", "to_hash"); -} - static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { @@ -1189,20 +1177,6 @@ mrb_hash_empty_m(mrb_state *mrb, mrb_value self) return mrb_bool_value(mrb_hash_empty_p(mrb, self)); } -/* 15.2.13.4.29 (x)*/ -/* - * call-seq: - * hsh.to_hash => hsh - * - * Returns +self+. - */ - -static mrb_value -mrb_hash_to_hash(mrb_state *mrb, mrb_value hash) -{ - return hash; -} - static int hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p) { @@ -1439,6 +1413,4 @@ mrb_init_hash(mrb_state *mrb) mrb_define_method(mrb, h, "value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.27 */ mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */ mrb_define_method(mrb, h, "rehash", mrb_hash_rehash, MRB_ARGS_NONE()); - - mrb_define_method(mrb, h, "to_hash", mrb_hash_to_hash, MRB_ARGS_NONE()); /* 15.2.13.4.29 (x)*/ } diff --git a/src/object.c b/src/object.c index a105c62f0..66dfa0f97 100644 --- a/src/object.c +++ b/src/object.c @@ -623,6 +623,23 @@ mrb_check_array_type(mrb_state *mrb, mrb_value ary) return ary; } +MRB_API mrb_value +mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash) +{ + if (!mrb_hash_p(hash)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Hash", + inspect_type(mrb, hash)); + } + return hash; +} + +MRB_API mrb_value +mrb_check_hash_type(mrb_state *mrb, mrb_value hash) +{ + if (!mrb_hash_p(hash)) return mrb_nil_value(); + return hash; +} + MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { -- cgit v1.2.3 From 9516731329a9d43b4aab57a19fb9cfc1b62f11e8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 12:01:58 +0900 Subject: Use type checking `mrb_to_str` instead of converting `mrb_str_to_str`. --- include/mruby/string.h | 1 + mrbgems/mruby-sprintf/src/sprintf.c | 2 +- mrbgems/mruby-struct/src/struct.c | 2 +- src/error.c | 2 +- src/string.c | 18 ++++++++---------- 5 files changed, 12 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/include/mruby/string.h b/include/mruby/string.h index fa1955f48..60db35c99 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -352,6 +352,7 @@ MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck); /* * Returns a converted string type. + * For type checking, non converting `mrb_to_str` is recommended. */ MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str); diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 5a4a7899e..985ffe276 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -552,7 +552,7 @@ mrb_str_format(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value fm ++argc; --argv; - fmt = mrb_str_to_str(mrb, fmt); + mrb_to_str(mrb, fmt); p = RSTRING_PTR(fmt); end = p + RSTRING_LEN(fmt); blen = 0; diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index b567a00d5..832583f35 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -213,7 +213,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass *kl } else { /* old style: should we warn? */ - name = mrb_str_to_str(mrb, name); + mrb_to_str(mrb, name); id = mrb_obj_to_sym(mrb, name); if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) { mrb_name_error(mrb, id, "identifier %S needs to be constant", name); diff --git a/src/error.c b/src/error.c index 599612b97..57cdfcfe1 100644 --- a/src/error.c +++ b/src/error.c @@ -28,7 +28,7 @@ mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len) MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) { - str = mrb_str_to_str(mrb, str); + mrb_to_str(mrb, str); return mrb_obj_new(mrb, c, 1, &str); } diff --git a/src/string.c b/src/string.c index b6d4ecef0..287b4dcbb 100644 --- a/src/string.c +++ b/src/string.c @@ -748,9 +748,7 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) MRB_API void mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) { - if (!mrb_string_p(other)) { - other = mrb_str_to_str(mrb, other); - } + other = mrb_str_to_str(mrb, other); mrb_str_cat_str(mrb, self, other); } @@ -993,15 +991,15 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) MRB_API const char* mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) { - mrb_value str = mrb_str_to_str(mrb, ptr); - return RSTRING_PTR(str); + mrb_to_str(mrb, ptr); + return RSTRING_PTR(ptr); } MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value ptr) { - mrb_value str = mrb_str_to_str(mrb, ptr); - return RSTRING_LEN(str); + mrb_to_str(mrb, ptr); + return RSTRING_LEN(ptr); } void @@ -2183,7 +2181,7 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - mrb_value str = mrb_str_to_str(mrb, *ptr); + mrb_value str = mrb_to_str(mrb, *ptr); struct RString *ps = mrb_str_ptr(str); mrb_int len = mrb_str_strlen(mrb, ps); char *p = RSTR_PTR(ps); @@ -2313,7 +2311,7 @@ mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) char *s; mrb_int len; - str = mrb_str_to_str(mrb, str); + mrb_to_str(mrb, str); s = RSTRING_PTR(str); len = RSTRING_LEN(str); if (s) { @@ -2600,7 +2598,7 @@ mrb_str_cat_str(mrb_state *mrb, mrb_value str, mrb_value str2) MRB_API mrb_value mrb_str_append(mrb_state *mrb, mrb_value str1, mrb_value str2) { - str2 = mrb_str_to_str(mrb, str2); + mrb_to_str(mrb, str2); return mrb_str_cat_str(mrb, str1, str2); } -- cgit v1.2.3 From 87ffab5713a49cef7133eeff7085b9c6a6a427fb Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 15:25:42 +0900 Subject: Adjust codedump output format; ref #4166 --- src/codedump.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/codedump.c b/src/codedump.c index 7d1950f75..4d56fd427 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -17,6 +17,7 @@ print_r(mrb_state *mrb, mrb_irep *irep, size_t n) if (irep->lv[i].r == n) { mrb_sym sym = irep->lv[i].name; printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym)); + break; } } } @@ -81,8 +82,9 @@ codedump(mrb_state *mrb, mrb_irep *irep) printf("local variable names:\n"); for (i = 1; i < irep->nlocals; ++i) { - char const *n = mrb_sym2name(mrb, irep->lv[i - 1].name); - printf(" R%d:%s\n", irep->lv[i - 1].r, n? n : ""); + char const *s = mrb_sym2name(mrb, irep->lv[i - 1].name); + int n = irep->lv[i - 1].r ? irep->lv[i - 1].r : i; + printf(" R%d:%s\n", n, s ? s : ""); } } -- cgit v1.2.3 From c308a149f0eaa529d5b3236e696aed13a19733ae Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 15:35:59 +0900 Subject: Add Hash type check for `OP_KARG` and `OP_KEY_P`; ref #4166 --- src/vm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 2d12df4ba..6bb9a48a5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1892,7 +1892,7 @@ RETRY_TRY_BLOCK: mrb_value k = mrb_symbol_value(syms[b]); mrb_value kdict = regs[mrb->c->ci->argc]; - if (!mrb_hash_key_p(mrb, kdict, k)) { + if (!mrb_hash_p(kdict) || !mrb_hash_key_p(mrb, kdict, k)) { mrb_value str = mrb_format(mrb, "missing keyword: %S", k); mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str)); goto L_RAISE; @@ -1905,8 +1905,11 @@ RETRY_TRY_BLOCK: CASE(OP_KEY_P, BB) { mrb_value k = mrb_symbol_value(syms[b]); mrb_value kdict = regs[mrb->c->ci->argc]; - mrb_bool key_p = mrb_hash_key_p(mrb, kdict, k); + mrb_bool key_p = FALSE; + if (mrb_hash_p(kdict)) { + key_p = mrb_hash_key_p(mrb, kdict, k); + } regs[a] = mrb_bool_value(key_p); NEXT; } -- cgit v1.2.3 From 53e2df3e93eea99f70950eebae766ce042769adb Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 16:13:26 +0900 Subject: Restore `mrb_string_type` function for compatibility. --- include/mruby/string.h | 4 ++++ src/object.c | 7 +++++++ 2 files changed, 11 insertions(+) (limited to 'src') diff --git a/include/mruby/string.h b/include/mruby/string.h index 60db35c99..1a20cb1de 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -313,6 +313,10 @@ MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb */ MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str); +/* obsolete: use mrb_ensure_string_type() instead */ +MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); + + MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa); MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); diff --git a/src/object.c b/src/object.c index 66dfa0f97..b764fc8ef 100644 --- a/src/object.c +++ b/src/object.c @@ -589,6 +589,13 @@ mrb_to_str(mrb_state *mrb, mrb_value val) return val; } +/* obsolete: use mrb_ensure_string_type() instead */ +MRB_API mrb_value +mrb_string_type(mrb_state *mrb, mrb_value str) +{ + return mrb_ensure_string_type(mrb, str); +} + MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str) { -- cgit v1.2.3 From 65a2c2082d97ea5fe2b7551bf73fbcefb5ca498e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 17:11:19 +0900 Subject: Call `mrb_str_to_str` from `mrb_string_value_ptr` for compatibility. --- src/string.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 287b4dcbb..2668a2c85 100644 --- a/src/string.c +++ b/src/string.c @@ -989,10 +989,10 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) } MRB_API const char* -mrb_string_value_ptr(mrb_state *mrb, mrb_value ptr) +mrb_string_value_ptr(mrb_state *mrb, mrb_value str) { - mrb_to_str(mrb, ptr); - return RSTRING_PTR(ptr); + str = mrb_str_to_str(mrb, str); + return RSTRING_PTR(str); } MRB_API mrb_int -- cgit v1.2.3 From 86d102350b4e68ae7ad4c1fef684f53a275790dc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 20 Nov 2018 09:14:34 +0900 Subject: Restrict total recursion number of `ecall()`; fix #3789 --- include/mruby.h | 3 ++- src/vm.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 12df9cd5a..5ff7a1d7b 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -267,7 +267,8 @@ typedef struct mrb_state { #else mrb_atexit_func *atexit_stack; #endif - mrb_int atexit_stack_len; + uint16_t atexit_stack_len; + uint16_t ecall_nest; /* prevent infinite recursive ecall() */ } mrb_state; /** diff --git a/src/vm.c b/src/vm.c index 6bb9a48a5..84e076ee8 100644 --- a/src/vm.c +++ b/src/vm.c @@ -55,7 +55,7 @@ void abort(void); /* Maximum depth of ecall() recursion. */ #ifndef MRB_ECALL_DEPTH_MAX -#define MRB_ECALL_DEPTH_MAX 32 +#define MRB_ECALL_DEPTH_MAX 512 #endif /* Maximum stack depth. Should be set lower on memory constrained systems. @@ -337,7 +337,8 @@ ecall(mrb_state *mrb) int nregs; if (i<0) return; - if (ci - c->cibase > MRB_ECALL_DEPTH_MAX) { + /* restrict total call depth of ecall() */ + if (++mrb->ecall_nest > MRB_ECALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = c->ensure[i]; @@ -372,6 +373,7 @@ ecall(mrb_state *mrb) c->ci = c->cibase + cioff; if (!mrb->exc) mrb->exc = exc; mrb_gc_arena_restore(mrb, ai); + mrb->ecall_nest--; } #ifndef MRB_FUNCALL_ARGC_MAX -- cgit v1.2.3 From c23e68d32b8913f35e344844805d1b80f5633ecd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 10 Dec 2018 10:23:01 +0900 Subject: Need to clear stack before invoking a block; fix #4181 --- src/vm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 84e076ee8..b5249b325 100644 --- a/src/vm.c +++ b/src/vm.c @@ -667,10 +667,11 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) return MRB_PROC_CFUNC(p)(mrb, self); } nregs = p->body.irep->nregs; - mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs); + if (nregs < 3) nregs = 3; + mrb_stack_extend(mrb, nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; - mrb->c->stack[2] = mrb_nil_value(); + stack_clear(mrb->c->stack+2, nregs-2); ci = cipush(mrb); ci->target_class = 0; ci->pc = p->body.irep->iseq; -- cgit v1.2.3 From c0d91a14e78de39b3940e56d4cccdbdb17b65694 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 09:01:05 +0900 Subject: Add API function `mrb_hash_foreach()` to iterate over items in a hash. --- include/mruby/hash.h | 4 ++++ src/hash.c | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 7811894ae..9b20bf9e6 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -210,6 +210,10 @@ void mrb_gc_mark_hash(mrb_state*, struct RHash*); size_t mrb_gc_mark_hash_size(mrb_state*, struct RHash*); void mrb_gc_free_hash(mrb_state*, struct RHash*); +/* return non zero to break the loop */ +typedef int (ht_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data); +MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p); + MRB_END_DECL #endif /* MRUBY_HASH_H */ diff --git a/src/hash.c b/src/hash.c index 467b20a51..00d5ad2b1 100644 --- a/src/hash.c +++ b/src/hash.c @@ -16,9 +16,6 @@ mrb_int mrb_float_id(mrb_float f); #endif -/* return non zero to break the loop */ -typedef int (ht_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); - #ifndef MRB_HT_INIT_SIZE #define MRB_HT_INIT_SIZE 4 #endif @@ -522,6 +519,13 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) } } +/* Iterates over the instance variable table. */ +MRB_API void +mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p) +{ + ht_foreach(mrb, hash->ht, func, p); +} + /* Copy the instance variable table. */ static htable* ht_copy(mrb_state *mrb, htable *t) -- cgit v1.2.3 From 378c728338c7dd828daf32468b4ce4f73fae4cb6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 09:04:08 +0900 Subject: Update comments. --- src/hash.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 00d5ad2b1..5920fe2c3 100644 --- a/src/hash.c +++ b/src/hash.c @@ -38,7 +38,7 @@ typedef struct segindex { struct segkv *table[]; } segindex; -/* Instance variable table structure */ +/* hash table structure */ typedef struct htable { segment *rootseg; segment *lastseg; @@ -132,7 +132,7 @@ ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b) } } -/* Creates the instance variable table. */ +/* Creates the hash table. */ static htable* ht_new(mrb_state *mrb) { @@ -346,7 +346,7 @@ ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) t->size++; } -/* Set the value for the key in the table. */ +/* Set the value for the key in the hash table. */ static void ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) { @@ -465,7 +465,7 @@ ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Deletes the value for the symbol from the instance variable table. */ +/* Deletes the value for the symbol from the hash table. */ /* Deletion is done by overwriting keys by `undef`. */ static mrb_bool ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) @@ -496,7 +496,7 @@ ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Iterates over the instance variable table. */ +/* Iterates over the hash table. */ static void ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) { @@ -519,14 +519,14 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) } } -/* Iterates over the instance variable table. */ +/* Iterates over the hash table. */ MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p) { ht_foreach(mrb, hash->ht, func, p); } -/* Copy the instance variable table. */ +/* Copy the hash table. */ static htable* ht_copy(mrb_state *mrb, htable *t) { @@ -552,7 +552,7 @@ ht_copy(mrb_state *mrb, htable *t) return t2; } -/* Free memory of the instance variable table. */ +/* Free memory of the hash table. */ static void ht_free(mrb_state *mrb, htable *t) { @@ -1012,7 +1012,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } -/* find first element in a hash table, and remove it. */ +/* find first element in the hash table, and remove it. */ static void ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp) { -- cgit v1.2.3 From f6b2e6231a1c07438915c2d32ab6002c2a2256b9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 09:47:06 +0900 Subject: Update `iv_foreach()` function. * return `void` instead of `mrb_bool'. * non zero return value from `func` breaks the loop. * no longer remove items on negative return value from `func`. --- src/variable.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 72c13aa1f..669a4f5cd 100644 --- a/src/variable.c +++ b/src/variable.c @@ -156,14 +156,13 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) } /* Iterates over the instance variable table. */ -static mrb_bool +static void iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) { segment *seg; size_t i; - int n; - if (t == NULL) return TRUE; + if (t == NULL) return; seg = t->rootseg; while (seg) { for (i=0; inext && i >= t->last_len) { - return FALSE; + return; } if (key != 0) { - n =(*func)(mrb, key, seg->val[i], p); - if (n > 0) return FALSE; - if (n < 0) { - t->size--; - seg->key[i] = 0; + if ((*func)(mrb, key, seg->val[i], p) != 0) { + return; } } } seg = seg->next; } - return TRUE; + return; } /* Get the size of the instance variable table. */ -- cgit v1.2.3 From a0df27d8e04f5d042040c794b79b9b213e7092e0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 09:48:15 +0900 Subject: Add new API `mrb_iv_foreach()` to iterate over instance variables. --- include/mruby/variable.h | 4 ++++ src/variable.c | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/mruby/variable.h b/include/mruby/variable.h index a0fbca1f9..c031567ea 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -131,6 +131,10 @@ void mrb_gc_mark_iv(mrb_state*, struct RObject*); size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*); void mrb_gc_free_iv(mrb_state*, struct RObject*); +/* return non zero to break the loop */ +typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, iv_foreach_func *func, void *p); + MRB_END_DECL #endif /* MRUBY_VARIABLE_H */ diff --git a/src/variable.c b/src/variable.c index 669a4f5cd..fafec81bd 100644 --- a/src/variable.c +++ b/src/variable.c @@ -9,8 +9,7 @@ #include #include #include - -typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +#include #ifndef MRB_IV_SEGMENT_SIZE #define MRB_IV_SEGMENT_SIZE 4 @@ -359,6 +358,14 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } +/* Iterates over the instance variable table. */ +MRB_API void +mrb_iv_foreach(mrb_state *mrb, mrb_value obj, iv_foreach_func *func, void *p) +{ + if (!obj_iv_p(obj)) return; + iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p); +} + static inline mrb_bool namespace_p(enum mrb_vtype tt) { -- cgit v1.2.3 From e935d20ab52ddc68d4d55444d0fa3974b035c098 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 10:39:53 +0900 Subject: Add `mrb_` prefix to `iv_foreach_func`. --- include/mruby/variable.h | 4 ++-- src/variable.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/mruby/variable.h b/include/mruby/variable.h index c031567ea..68a2a7121 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -132,8 +132,8 @@ size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*); void mrb_gc_free_iv(mrb_state*, struct RObject*); /* return non zero to break the loop */ -typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); -MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, iv_foreach_func *func, void *p); +typedef int (mrb_iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p); MRB_END_DECL diff --git a/src/variable.c b/src/variable.c index fafec81bd..14e9da9ef 100644 --- a/src/variable.c +++ b/src/variable.c @@ -156,7 +156,7 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) /* Iterates over the instance variable table. */ static void -iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) +iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p) { segment *seg; size_t i; @@ -360,7 +360,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) /* Iterates over the instance variable table. */ MRB_API void -mrb_iv_foreach(mrb_state *mrb, mrb_value obj, iv_foreach_func *func, void *p) +mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) { if (!obj_iv_p(obj)) return; iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p); -- cgit v1.2.3 From 265171a28c2805ae49d0ad70d0f35220b4cb4d4b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 10:41:26 +0900 Subject: Rename `ht_foreach_func` to `mrb_hash_foreach_func`. --- include/mruby/hash.h | 4 ++-- src/hash.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 9b20bf9e6..911a96042 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -211,8 +211,8 @@ size_t mrb_gc_mark_hash_size(mrb_state*, struct RHash*); void mrb_gc_free_hash(mrb_state*, struct RHash*); /* return non zero to break the loop */ -typedef int (ht_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data); -MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p); +typedef int (mrb_hash_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data); +MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p); MRB_END_DECL diff --git a/src/hash.c b/src/hash.c index 5920fe2c3..cb4a274e8 100644 --- a/src/hash.c +++ b/src/hash.c @@ -498,7 +498,7 @@ ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) /* Iterates over the hash table. */ static void -ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) +ht_foreach(mrb_state *mrb, htable *t, mrb_hash_foreach_func *func, void *p) { segment *seg; mrb_int i; @@ -521,7 +521,7 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) /* Iterates over the hash table. */ MRB_API void -mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, ht_foreach_func *func, void *p) +mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p) { ht_foreach(mrb, hash->ht, func, p); } -- cgit v1.2.3 From 60da293d5c4f4d00798f06ad955ea12311b6fd68 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 11 Dec 2018 10:54:47 +0900 Subject: Avoid using floating point number for HT_SEG_INCREASE_RATIO; ref #4182 --- src/hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index cb4a274e8..3d6c2ed7d 100644 --- a/src/hash.c +++ b/src/hash.c @@ -19,7 +19,7 @@ mrb_int mrb_float_id(mrb_float f); #ifndef MRB_HT_INIT_SIZE #define MRB_HT_INIT_SIZE 4 #endif -#define HT_SEG_INCREASE_RATIO 1.2 +#define HT_SEG_INCREASE_RATIO 6 / 5 struct segkv { mrb_value key; -- cgit v1.2.3 From 62dd4d89fc6da2c38a9bc1913c1f25566a9e443e Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 14 Dec 2018 21:41:07 +0900 Subject: Add `mrb_hash_size()` function. --- include/mruby/hash.h | 13 +++++++++++++ src/hash.c | 14 ++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 911a96042..ce51b2016 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -165,6 +165,19 @@ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash); */ MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); +/* + * Get hash size. + * + * Equivalent to: + * + * hash.size + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return The hash size. + */ +MRB_API mrb_int mrb_hash_size(mrb_state *mrb, mrb_value hash); + /* * Copies the hash. * diff --git a/src/hash.c b/src/hash.c index 3d6c2ed7d..2f60eb74a 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1133,6 +1133,15 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) return val; } +MRB_API mrb_int +mrb_hash_size(mrb_state *mrb, mrb_value hash) +{ + htable *t = RHASH_TBL(hash); + + if (!t) return 0; + return t->size; +} + /* 15.2.13.4.20 */ /* 15.2.13.4.25 */ /* @@ -1150,10 +1159,7 @@ mrb_hash_aset(mrb_state *mrb, mrb_value self) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - htable *t = RHASH_TBL(self); - - if (!t) return mrb_fixnum_value(0); - return mrb_fixnum_value(t->size); + return mrb_fixnum_value(mrb_hash_size(mrb, self)); } MRB_API mrb_bool -- cgit v1.2.3 From d8c70167f736dc4c3828f008658b69cd45f93363 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Sat, 15 Dec 2018 05:17:38 +0900 Subject: Make mrb_ary_clear() function callable from C again --- src/array.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 084b48dc0..707820ab9 100644 --- a/src/array.c +++ b/src/array.c @@ -1089,7 +1089,6 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); - mrb_get_args(mrb, ""); ary_modify(mrb, a); if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->as.heap.aux.shared); @@ -1103,6 +1102,13 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) return self; } +static mrb_value +mrb_ary_clear_m(mrb_state *mrb, mrb_value self) +{ + mrb_get_args(mrb, ""); + return mrb_ary_clear(mrb, self); +} + static mrb_value mrb_ary_empty_p(mrb_state *mrb, mrb_value self) { @@ -1268,7 +1274,7 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ - mrb_define_method(mrb, a, "clear", mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ + mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ -- cgit v1.2.3 From c03fa0e1b3acea696c8715a679915bb58b067403 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Dec 2018 15:47:17 +0900 Subject: Recover `String#to_str`; ref #4177 We have removed implicit conversion to strings using `to_str`. But some people still using `to_str` as a typical string method, i.e. they do string check by code like: `obj.respond_to?(:to_str)`. So we have recovered the method. --- src/string.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index 2668a2c85..52941473c 100644 --- a/src/string.c +++ b/src/string.c @@ -2754,6 +2754,7 @@ mrb_init_string(mrb_state *mrb) #endif mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */ mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ + mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ -- cgit v1.2.3 From e690314525d3ebfa23eda9f2cacfff37bd53482a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Dec 2018 15:52:04 +0900 Subject: Recover `#to_int`; ref #4177 We have removed implicit conversion to strings using `to_int`. But some users still using `to_int` as a typical integer method, i.e. they do string check by code like: `obj.respond_to?(:to_int)`. So we have recovered the method. --- src/numeric.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 3624831cc..077ae30aa 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1511,6 +1511,7 @@ mrb_init_numeric(mrb_state *mrb) MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM); mrb_undef_class_method(mrb, integer, "new"); mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ + mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ @@ -1562,6 +1563,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ + mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ -- cgit v1.2.3 From ccc5edc60dd8f60d4e829586ac5541cb6f4e9461 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 17 Dec 2018 16:00:22 +0900 Subject: Small refactoring of #4188 --- src/hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 2f60eb74a..6b92344c3 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1159,7 +1159,8 @@ mrb_hash_size(mrb_state *mrb, mrb_value hash) static mrb_value mrb_hash_size_m(mrb_state *mrb, mrb_value self) { - return mrb_fixnum_value(mrb_hash_size(mrb, self)); + mrb_int size = mrb_hash_size(mrb, self); + return mrb_fixnum_value(size); } MRB_API mrb_bool -- cgit v1.2.3 From b0dc163b5dadbdc8ef2241f3aa56a1eae428a22a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 23 Dec 2018 14:19:09 +0900 Subject: Suppress a struct initializer warning Suppress a compiler (clang) warning bellow: src/vm.c:104:38: warning: suggest braces around initialization of subobject [-Wmissing-braces] const mrb_value mrb_value_zero = { 0 }; ^ {} --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index b5249b325..49c2bb85c 100644 --- a/src/vm.c +++ b/src/vm.c @@ -101,7 +101,7 @@ static inline void stack_clear(mrb_value *from, size_t count) { #ifndef MRB_NAN_BOXING - const mrb_value mrb_value_zero = { 0 }; + const mrb_value mrb_value_zero = { { 0 } }; while (count-- > 0) { *from++ = mrb_value_zero; -- cgit v1.2.3 From 648b57620a6f0bd03ab11db61b1fee343c889dfe Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 1 Jan 2019 15:35:56 +0900 Subject: range: Embed edges in RRange on boxing environment. [Breaking changes] Developers must use following APIs for accessing attributes of RRange because RRange structure depends on boxing setting. - mrb_range_beg - mrb_range_end - mrb_range_excl_p --- include/mruby/range.h | 34 ++++++-- mrbgems/mruby-range-ext/src/range.c | 15 ++-- src/gc.c | 11 +-- src/range.c | 161 +++++++++++++++++++++--------------- test/t/range.rb | 16 ++++ 5 files changed, 147 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/include/mruby/range.h b/include/mruby/range.h index b166e586b..4df5ccc70 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -14,20 +14,43 @@ */ MRB_BEGIN_DECL +#if defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING) +# define MRB_RANGE_EMBED +#endif + +#ifdef MRB_RANGE_EMBED +struct RRange { + MRB_OBJECT_HEADER; + mrb_value beg; + mrb_value end; + mrb_bool excl; +}; +# define mrb_gc_free_range(mrb, p) ((void)0) +# define RANGE_BEG(p) ((p)->beg) +# define RANGE_END(p) ((p)->end) +#else typedef struct mrb_range_edges { mrb_value beg; mrb_value end; } mrb_range_edges; - struct RRange { MRB_OBJECT_HEADER; mrb_range_edges *edges; - mrb_bool excl : 1; + mrb_bool excl; }; +# define mrb_gc_free_range(mrb, p) mrb_free(mrb, ((struct RRange*)p)->edges) +# define RANGE_BEG(p) ((p)->edges->beg) +# define RANGE_END(p) ((p)->edges->end) +#endif + +#define mrb_range_beg(mrb, r) RANGE_BEG(mrb_range_ptr(mrb, r)) +#define mrb_range_end(mrb, r) RANGE_END(mrb_range_ptr(mrb, r)) +#define mrb_range_excl_p(mrb, r) RANGE_EXCL(mrb_range_ptr(mrb, r)) +#define mrb_range_raw_ptr(r) ((struct RRange*)mrb_ptr(r)) +#define mrb_range_value(p) mrb_obj_value((void*)(p)) +#define RANGE_EXCL(p) ((p)->excl) -MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v); -#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v)) -#define mrb_range_value(p) mrb_obj_value((void*)(p)) +MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value range); /* * Initializes a Range. @@ -43,6 +66,7 @@ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); +void mrb_gc_mark_range(mrb_state *mrb, struct RRange *r); MRB_END_DECL diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index aca71cc01..1fc383755 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -48,11 +48,11 @@ mrb_range_cover(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &val); - beg = r->edges->beg; - end = r->edges->end; + beg = RANGE_BEG(r); + end = RANGE_END(r); if (r_le(mrb, beg, val)) { - if (r->excl) { + if (RANGE_EXCL(r)) { if (r_lt(mrb, val, end)) return mrb_true_value(); } @@ -86,10 +86,9 @@ mrb_range_last(mrb_state *mrb, mrb_value range) { mrb_value num; mrb_value array; - struct RRange *r = mrb_range_ptr(mrb, range); if (mrb_get_args(mrb, "|o", &num) == 0) { - return r->edges->end; + return mrb_range_end(mrb, range); } array = mrb_funcall(mrb, range, "to_a", 0); @@ -116,9 +115,9 @@ mrb_range_size(mrb_state *mrb, mrb_value range) mrb_bool num_p = TRUE; mrb_bool excl; - beg = r->edges->beg; - end = r->edges->end; - excl = r->excl; + beg = RANGE_BEG(r); + end = RANGE_END(r); + excl = RANGE_EXCL(r); if (mrb_fixnum_p(beg)) { beg_f = (mrb_float)mrb_fixnum(beg); } diff --git a/src/gc.c b/src/gc.c index a52c64bfa..ec52787e8 100644 --- a/src/gc.c +++ b/src/gc.c @@ -739,14 +739,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) break; case MRB_TT_RANGE: - { - struct RRange *r = (struct RRange*)obj; - - if (r->edges) { - mrb_gc_mark_value(mrb, r->edges->beg); - mrb_gc_mark_value(mrb, r->edges->end); - } - } + mrb_gc_mark_range(mrb, (struct RRange*)obj); break; default: @@ -870,7 +863,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) break; case MRB_TT_RANGE: - mrb_free(mrb, ((struct RRange*)obj)->edges); + mrb_gc_free_range(mrb, ((struct RRange*)obj)); break; case MRB_TT_DATA: diff --git a/src/range.c b/src/range.c index e45308d35..d2f897bd5 100644 --- a/src/range.c +++ b/src/range.c @@ -10,12 +10,17 @@ #include #include +#define RANGE_INITIALIZED_MASK 1 +#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK) +#define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK) + MRB_API struct RRange* -mrb_range_ptr(mrb_state *mrb, mrb_value v) +mrb_range_ptr(mrb_state *mrb, mrb_value range) { - struct RRange *r = (struct RRange*)mrb_ptr(v); + struct RRange *r = mrb_range_raw_ptr(range); - if (r->edges == NULL) { + /* check for if #initialize_copy was removed [#3320] */ + if (!RANGE_INITIALIZED_P(r)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); } return r; @@ -46,17 +51,52 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } -MRB_API mrb_value -mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +static void +range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) { - struct RRange *r; +#ifndef MRB_RANGE_EMBED + r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); +#endif +} +static struct RRange * +range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ range_check(mrb, beg, end); - r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - r->edges->beg = beg; - r->edges->end = end; - r->excl = excl; + + if (r) { + if (RANGE_INITIALIZED_P(r)) { + /* Ranges are immutable, so that they should be initialized only once. */ + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + } + else { + range_ptr_alloc_edges(mrb, r); + } + } + else { + r = (struct RRange*)mrb_obj_alloc(mrb, MRB_TT_RANGE, mrb->range_class); + range_ptr_alloc_edges(mrb, r); + } + + RANGE_BEG(r) = beg; + RANGE_END(r) = end; + RANGE_EXCL(r) = excl; + RANGE_INITIALIZED(r); + + return r; +} + +static void +range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) +{ + range_ptr_init(mrb, r, beg, end, excl); + mrb_write_barrier(mrb, (struct RBasic*)r); +} + +MRB_API mrb_value +mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +{ + struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); return mrb_range_value(r); } @@ -67,12 +107,10 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) * * Returns the first object in rng. */ -mrb_value -mrb_range_beg(mrb_state *mrb, mrb_value range) +static mrb_value +range_beg(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->beg; + return mrb_range_beg(mrb, range); } /* @@ -86,12 +124,10 @@ mrb_range_beg(mrb_state *mrb, mrb_value range) * (1...10).end #=> 10 */ -mrb_value -mrb_range_end(mrb_state *mrb, mrb_value range) +static mrb_value +range_end(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return r->edges->end; + return mrb_range_end(mrb, range); } /* @@ -103,25 +139,9 @@ mrb_range_end(mrb_state *mrb, mrb_value range) mrb_value mrb_range_excl(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(mrb, range); - - return mrb_bool_value(r->excl); + return mrb_bool_value(mrb_range_excl_p(mrb, range)); } -static void -range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) -{ - struct RRange *r = mrb_range_raw_ptr(range); - - range_check(mrb, beg, end); - r->excl = exclude_end; - if (!r->edges) { - r->edges = (mrb_range_edges *)mrb_malloc(mrb, sizeof(mrb_range_edges)); - } - r->edges->beg = beg; - r->edges->end = end; - mrb_write_barrier(mrb, (struct RBasic*)r); -} /* * call-seq: * Range.new(start, end, exclusive=false) => range @@ -142,11 +162,7 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) if (n != 3) { exclusive = FALSE; } - /* Ranges are immutable, so that they should be initialized only once. */ - if (mrb_range_raw_ptr(range)->edges) { - mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); - } - range_init(mrb, range, beg, end, exclusive); + range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } /* @@ -180,9 +196,9 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) rr = mrb_range_ptr(mrb, range); ro = mrb_range_ptr(mrb, obj); - v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg); - v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end); - if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) { + v1 = mrb_funcall(mrb, RANGE_BEG(rr), "==", 1, RANGE_BEG(ro)); + v2 = mrb_funcall(mrb, RANGE_END(rr), "==", 1, RANGE_END(ro)); + if (!mrb_bool(v1) || !mrb_bool(v2) || RANGE_EXCL(rr) != RANGE_EXCL(ro)) { return mrb_false_value(); } return mrb_true_value(); @@ -242,11 +258,11 @@ mrb_range_include(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &val); - beg = r->edges->beg; - end = r->edges->end; - include_p = r_le(mrb, beg, val) && /* beg <= val */ - (r->excl ? r_gt(mrb, end, val) /* end > val */ - : r_ge(mrb, end, val)); /* end >= val */ + beg = RANGE_BEG(r); + end = RANGE_END(r); + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (RANGE_EXCL(r) ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ return mrb_bool_value(include_p); } @@ -260,8 +276,8 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, if (mrb_type(range) != MRB_TT_RANGE) return 0; r = mrb_range_ptr(mrb, range); - beg = mrb_int(mrb, r->edges->beg); - end = mrb_int(mrb, r->edges->end); + beg = mrb_int(mrb, RANGE_BEG(r)); + end = mrb_int(mrb, RANGE_END(r)); if (beg < 0) { beg += len; @@ -274,7 +290,7 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, } if (end < 0) end += len; - if (!r->excl && (!trunc || end < len)) + if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */ len = end - beg; if (len < 0) len = 0; @@ -298,10 +314,10 @@ range_to_s(mrb_state *mrb, mrb_value range) mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_obj_as_string(mrb, r->edges->beg); - str2 = mrb_obj_as_string(mrb, r->edges->end); + str = mrb_obj_as_string(mrb, RANGE_BEG(r)); + str2 = mrb_obj_as_string(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -323,10 +339,10 @@ range_inspect(mrb_state *mrb, mrb_value range) mrb_value str, str2; struct RRange *r = mrb_range_ptr(mrb, range); - str = mrb_inspect(mrb, r->edges->beg); - str2 = mrb_inspect(mrb, r->edges->end); + str = mrb_inspect(mrb, RANGE_BEG(r)); + str2 = mrb_inspect(mrb, RANGE_END(r)); str = mrb_str_dup(mrb, str); - mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2); + mrb_str_cat(mrb, str, "...", RANGE_EXCL(r) ? 3 : 2); mrb_str_cat_str(mrb, str, str2); return str; @@ -363,9 +379,9 @@ range_eql(mrb_state *mrb, mrb_value range) r = mrb_range_ptr(mrb, range); o = mrb_range_ptr(mrb, obj); - if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || - !mrb_eql(mrb, r->edges->end, o->edges->end) || - (r->excl != o->excl)) { + if (!mrb_eql(mrb, RANGE_BEG(r), RANGE_BEG(o)) || + !mrb_eql(mrb, RANGE_END(r), RANGE_END(o)) || + (RANGE_EXCL(r) != RANGE_EXCL(o))) { return mrb_false_value(); } return mrb_true_value(); @@ -386,7 +402,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) } r = mrb_range_ptr(mrb, src); - range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); + range_ptr_replace(mrb, mrb_range_raw_ptr(copy), RANGE_BEG(r), RANGE_END(r), RANGE_EXCL(r)); return copy; } @@ -420,6 +436,15 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con return result; } +void +mrb_gc_mark_range(mrb_state *mrb, struct RRange *r) +{ + if (RANGE_INITIALIZED_P(r)) { + mrb_gc_mark_value(mrb, RANGE_BEG(r)); + mrb_gc_mark_value(mrb, RANGE_END(r)); + } +} + void mrb_init_range(mrb_state *mrb) { @@ -429,15 +454,15 @@ mrb_init_range(mrb_state *mrb) mrb->range_class = r; MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE); - mrb_define_method(mrb, r, "begin", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ - mrb_define_method(mrb, r, "end", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ + mrb_define_method(mrb, r, "begin", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ + mrb_define_method(mrb, r, "end", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ - mrb_define_method(mrb, r, "first", mrb_range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ + mrb_define_method(mrb, r, "first", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ - mrb_define_method(mrb, r, "last", mrb_range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ + mrb_define_method(mrb, r, "last", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ diff --git a/test/t/range.rb b/test/t/range.rb index 5aee4d5cc..64e7f9d9f 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -93,3 +93,19 @@ assert('Range#eql?', '15.2.14.4.14') do assert_false (1..10).eql? (Range.new(1.0, 10.0)) assert_false (1..10).eql? "1..10" end + +assert('Range#initialize_copy', '15.2.14.4.15') do + assert_raise(NameError) { (0..1).__send__(:initialize_copy, 1..3) } +end + +assert('Range#dup') do + r = (1..3).dup + assert_equal r.begin, 1 + assert_equal r.end, 3 + assert_false r.exclude_end? + + r = ("a"..."z").dup + assert_equal r.begin, "a" + assert_equal r.end, "z" + assert_true r.exclude_end? +end -- cgit v1.2.3 From cca19532c5f71e1bdc0b4947b2fcddd181f27781 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 3 Jan 2019 11:34:35 +0900 Subject: Remove `Kernel#class_defined?` which is not available in CRuby; #3829 --- mrbgems/mruby-kernel-ext/test/kernel.rb | 6 ++- mrbgems/mruby-numeric-ext/test/numeric.rb | 3 +- mrbgems/mruby-object-ext/test/nil.rb | 3 +- mrbgems/mruby-objectspace/test/objectspace.rb | 2 +- mrbgems/mruby-sprintf/test/sprintf.rb | 9 +++-- mrblib/float.rb | 2 +- mrblib/numeric.rb | 2 +- src/kernel.c | 12 ------ test/t/array.rb | 3 +- test/t/class.rb | 2 +- test/t/float.rb | 4 +- test/t/hash.rb | 3 +- test/t/integer.rb | 54 +++++++++++++-------------- test/t/numeric.rb | 3 +- test/t/range.rb | 3 +- test/t/string.rb | 4 +- 16 files changed, 56 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb index 206b7ac74..28f089007 100644 --- a/mrbgems/mruby-kernel-ext/test/kernel.rb +++ b/mrbgems/mruby-kernel-ext/test/kernel.rb @@ -49,21 +49,23 @@ assert('Kernel#__method__') do end assert('Kernel#Integer') do - assert_equal(123, Integer(123.999)) if class_defined?("Float") assert_equal(26, Integer("0x1a")) assert_equal(930, Integer("0930", 10)) assert_equal(7, Integer("111", 2)) assert_equal(0, Integer("0")) assert_equal(0, Integer("00000")) assert_raise(TypeError) { Integer(nil) } + skip unless Object.const_defined?(:Float) + assert_equal(123, Integer(123.999)) end assert('Kernel#Float') do + skip unless Object.const_defined?(:Float) assert_equal(1.0, Float(1)) assert_equal(123.456, Float(123.456)) assert_equal(123.456, Float("123.456")) assert_raise(TypeError) { Float(nil) } -end if class_defined?("Float") +end assert('Kernel#String') do assert_equal("main", String(self)) diff --git a/mrbgems/mruby-numeric-ext/test/numeric.rb b/mrbgems/mruby-numeric-ext/test/numeric.rb index 6ea0c14e7..c85cb61f2 100644 --- a/mrbgems/mruby-numeric-ext/test/numeric.rb +++ b/mrbgems/mruby-numeric-ext/test/numeric.rb @@ -14,8 +14,9 @@ assert('Integer#div') do end assert('Float#div') do + skip unless Object.const_defined?(:Float) assert_float 52, 365.2425.div(7) -end if class_defined?("Float") +end assert('Integer#zero?') do assert_equal true, 0.zero? diff --git a/mrbgems/mruby-object-ext/test/nil.rb b/mrbgems/mruby-object-ext/test/nil.rb index 7f773637a..fbff20629 100644 --- a/mrbgems/mruby-object-ext/test/nil.rb +++ b/mrbgems/mruby-object-ext/test/nil.rb @@ -3,8 +3,9 @@ assert('NilClass#to_a') do end assert('NilClass#to_f') do + skip unless Object.const_defined?(:Float) assert_equal 0.0, nil.to_f -end if class_defined?("Float") +end assert('NilClass#to_i') do assert_equal 0, nil.to_i diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb index 0553b97e2..8db89eeaf 100644 --- a/mrbgems/mruby-objectspace/test/objectspace.rb +++ b/mrbgems/mruby-objectspace/test/objectspace.rb @@ -1,6 +1,6 @@ assert('ObjectSpace.count_objects') do h = {} - f = Fiber.new {} if Object.const_defined? :Fiber + f = Fiber.new {} if Object.const_defined?(:Fiber) ObjectSpace.count_objects(h) assert_kind_of(Hash, h) assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb index a5fd4e638..137812ae7 100644 --- a/mrbgems/mruby-sprintf/test/sprintf.rb +++ b/mrbgems/mruby-sprintf/test/sprintf.rb @@ -4,12 +4,14 @@ assert('String#%') do assert_equal "one=1", "one=%d" % 1 assert_equal "1 one", "%d %s" % [ 1, "one" ] - assert_equal "1.0", "%3.1f" % 1.01 if class_defined?("Float") assert_equal "123 < 456", "%{num} < %s" % { num: 123, str: "456" } assert_equal 15, ("%b" % (1<<14)).size + skip unless Object.const_defined?(:Float) + assert_equal "1.0", "%3.1f" % 1.01 end assert('String#% with inf') do + skip unless Object.const_defined?(:Float) inf = Float::INFINITY assert_equal "Inf", "%f" % inf @@ -35,9 +37,10 @@ assert('String#% with inf') do assert_equal " Inf", "% 3f" % inf assert_equal " Inf", "% 4f" % inf assert_equal " Inf", "% 5f" % inf -end if class_defined?("Float") +end assert('String#% with nan') do + skip unless Object.const_defined?(:Float) nan = Float::NAN assert_equal "NaN", "%f" % nan @@ -63,7 +66,7 @@ assert('String#% with nan') do assert_equal " NaN", "% 3f" % nan assert_equal " NaN", "% 4f" % nan assert_equal " NaN", "% 5f" % nan -end if class_defined?("Float") +end assert("String#% with invalid chr") do begin diff --git a/mrblib/float.rb b/mrblib/float.rb index 2b86dc1e5..421b8d851 100644 --- a/mrblib/float.rb +++ b/mrblib/float.rb @@ -6,4 +6,4 @@ class Float # mruby special - since mruby integers may be upgraded to floats, # floats should be compatible to integers. include Integral -end if class_defined?("Float") +end if Object.const_defined?(:Float) diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 1b11e92ad..a2eb9c450 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -104,7 +104,7 @@ module Integral raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block - i = if class_defined?("Float") && num.kind_of?(Float) then self.to_f else self end + i = if Object.const_defined?(:Float) && num.kind_of?(Float) then self.to_f else self end if num == nil while true block.call(i) diff --git a/src/kernel.c b/src/kernel.c index ce9cd1d44..8845cbce6 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -640,16 +640,6 @@ mrb_f_raise(mrb_state *mrb, mrb_value self) return mrb_nil_value(); /* not reached */ } -static mrb_value -mrb_krn_class_defined(mrb_state *mrb, mrb_value self) -{ - mrb_value str; - - mrb_get_args(mrb, "S", &str); - return mrb_bool_value(mrb_class_defined(mrb, RSTRING_PTR(str))); -} - - /* 15.3.1.3.41 */ /* * call-seq: @@ -847,8 +837,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ - mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); - mrb_include_module(mrb, mrb->object_class, mrb->kernel_module); mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */ } diff --git a/test/t/array.rb b/test/t/array.rb index 53fbdcf1a..c182d5e14 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -55,9 +55,10 @@ assert('Array#[]', '15.2.12.5.4') do assert_equal(nil, [1,2,3].[](-4)) a = [ "a", "b", "c", "d", "e" ] - assert_equal("b", a[1.1]) if class_defined?("Float") assert_equal(["b", "c"], a[1,2]) assert_equal(["b", "c", "d"], a[1..-2]) + skip unless Object.const_defined?(:Float) + assert_equal("b", a[1.1]) end assert('Array#[]=', '15.2.12.5.5') do diff --git a/test/t/class.rb b/test/t/class.rb index 85450f200..f37a891a4 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -350,7 +350,7 @@ assert('singleton tests') do 7 end end - end if class_defined?("Float") + end if Object.const_defined?(:Float) end assert('clone Class') do diff --git a/test/t/float.rb b/test/t/float.rb index 92f7a15f1..68fd31b9a 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -1,7 +1,7 @@ ## # Float ISO Test -if class_defined?("Float") +if Object.const_defined?(:Float) assert('Float', '15.2.9') do assert_equal Class, Float.class @@ -206,4 +206,4 @@ assert('Float#>>') do assert_equal(-1, -23.0 >> 128) end -end # class_defined?("Float") +end # const_defined?(:Float) diff --git a/test/t/hash.rb b/test/t/hash.rb index 8088bfa21..e3f917b6f 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -8,8 +8,9 @@ end assert('Hash#==', '15.2.13.4.1') do assert_true({ 'abc' => 'abc' } == { 'abc' => 'abc' }) assert_false({ 'abc' => 'abc' } == { 'cba' => 'cba' }) - assert_true({ :equal => 1 } == { :equal => 1.0 }) if class_defined?("Float") assert_false({ :a => 1 } == true) + skip unless Object.const_defined?(:Float) + assert_true({ :equal => 1 } == { :equal => 1.0 }) end assert('Hash#[]', '15.2.13.4.2') do diff --git a/test/t/integer.rb b/test/t/integer.rb index cea97a1e6..c37641e9f 100644 --- a/test/t/integer.rb +++ b/test/t/integer.rb @@ -7,10 +7,10 @@ end assert('Integer#+', '15.2.8.3.1') do a = 1+1 - b = 1+1.0 if class_defined?("Float") + b = 1+1.0 if Object.const_defined?(:Float) assert_equal 2, a - assert_equal 2.0, b if class_defined?("Float") + assert_equal 2.0, b if Object.const_defined?(:Float) assert_raise(TypeError){ 0+nil } assert_raise(TypeError){ 1+nil } @@ -18,40 +18,38 @@ assert('Integer#+', '15.2.8.3.1') do c = Mrbtest::FIXNUM_MAX + 1 d = Mrbtest::FIXNUM_MAX.__send__(:+, 1) - if class_defined?("Float") - e = Mrbtest::FIXNUM_MAX + 1.0 - assert_equal Float, c.class - assert_equal Float, d.class - assert_float e, c - assert_float e, d - end + skip unless Object.const_defined?(:Float) + e = Mrbtest::FIXNUM_MAX + 1.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#-', '15.2.8.3.2') do a = 2-1 - b = 2-1.0 if class_defined?("Float") + b = 2-1.0 if Object.const_defined?(:Float) assert_equal 1, a - assert_equal 1.0, b if class_defined?("Float") + assert_equal 1.0, b if Object.const_defined?(:Float) c = Mrbtest::FIXNUM_MIN - 1 d = Mrbtest::FIXNUM_MIN.__send__(:-, 1) - if class_defined?("Float") - e = Mrbtest::FIXNUM_MIN - 1.0 - assert_equal Float, c.class - assert_equal Float, d.class - assert_float e, c - assert_float e, d - end + skip unless Object.const_defined?(:Float) + e = Mrbtest::FIXNUM_MIN - 1.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#*', '15.2.8.3.3') do a = 1*1 - b = 1*1.0 if class_defined?("Float") + b = 1*1.0 if Object.const_defined?(:Float) assert_equal 1, a - assert_equal 1.0, b if class_defined?("Float") + assert_equal 1.0, b if Object.const_defined?(:Float) assert_raise(TypeError){ 0*nil } assert_raise(TypeError){ 1*nil } @@ -59,13 +57,12 @@ assert('Integer#*', '15.2.8.3.3') do c = Mrbtest::FIXNUM_MAX * 2 d = Mrbtest::FIXNUM_MAX.__send__(:*, 2) - if class_defined?("Float") - e = Mrbtest::FIXNUM_MAX * 2.0 - assert_equal Float, c.class - assert_equal Float, d.class - assert_float e, c - assert_float e, d - end + skip unless Object.const_defined?(:Float) + e = Mrbtest::FIXNUM_MAX * 2.0 + assert_equal Float, c.class + assert_equal Float, d.class + assert_float e, c + assert_float e, d end assert('Integer#/', '15.2.8.3.4') do @@ -226,8 +223,9 @@ assert('Integer#times', '15.2.8.3.22') do end assert('Integer#to_f', '15.2.8.3.23') do + skip unless Object.const_defined?(:Float) assert_equal 1.0, 1.to_f -end if class_defined?("Float") +end assert('Integer#to_i', '15.2.8.3.24') do assert_equal 1, 1.to_i diff --git a/test/t/numeric.rb b/test/t/numeric.rb index 38c62a669..9d6dc22cc 100644 --- a/test/t/numeric.rb +++ b/test/t/numeric.rb @@ -15,7 +15,8 @@ end assert('Numeric#abs', '15.2.7.4.3') do assert_equal(1, 1.abs) - assert_equal(1.0, -1.abs) if class_defined?("Float") + skip unless Object.const_defined?(:Float) + assert_equal(1.0, -1.abs) end assert('Numeric#pow') do diff --git a/test/t/range.rb b/test/t/range.rb index 64e7f9d9f..d71fe8946 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -8,7 +8,8 @@ end assert('Range#==', '15.2.14.4.1') do assert_true (1..10) == (1..10) assert_false (1..10) == (1..100) - assert_true (1..10) == Range.new(1.0, 10.0) if class_defined?("Float") + skip unless Object.const_defined?(:Float) + assert_true (1..10) == Range.new(1.0, 10.0) end assert('Range#===', '15.2.14.4.2') do diff --git a/test/t/string.rb b/test/t/string.rb index 3a1eced16..8f008c6a7 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -155,7 +155,7 @@ assert('String#[]=') do d[-10] = 'X' end - if class_defined?("Float") + if Object.const_defined?(:Float) e = 'abc' e[1.1] = 'X' assert_equal 'aXc', e @@ -618,7 +618,7 @@ assert('String#to_f', '15.2.10.5.38') do assert_float(12345.6789, c) assert_float(0, d) assert_float(Float::INFINITY, e) -end if class_defined?("Float") +end if Object.const_defined?(:Float) assert('String#to_i', '15.2.10.5.39') do a = ''.to_i -- cgit v1.2.3 From eb216fc858f2dbb05731699b87e1d59619577e9d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 3 Jan 2019 20:09:41 +0900 Subject: range: Refactor range.h/range.c Functions order, name, linkage and so on. --- include/mruby/range.h | 2 +- src/range.c | 229 +++++++++++++++++++++++--------------------------- 2 files changed, 108 insertions(+), 123 deletions(-) (limited to 'src') diff --git a/include/mruby/range.h b/include/mruby/range.h index 4df5ccc70..b5626993a 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -38,7 +38,7 @@ struct RRange { mrb_range_edges *edges; mrb_bool excl; }; -# define mrb_gc_free_range(mrb, p) mrb_free(mrb, ((struct RRange*)p)->edges) +# define mrb_gc_free_range(mrb, p) mrb_free(mrb, (p)->edges) # define RANGE_BEG(p) ((p)->edges->beg) # define RANGE_END(p) ((p)->edges->end) #endif diff --git a/src/range.c b/src/range.c index d2f897bd5..2f2521f5e 100644 --- a/src/range.c +++ b/src/range.c @@ -14,20 +14,8 @@ #define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_MASK) #define RANGE_INITIALIZED_P(p) ((p)->flags & RANGE_INITIALIZED_MASK) -MRB_API struct RRange* -mrb_range_ptr(mrb_state *mrb, mrb_value range) -{ - struct RRange *r = mrb_range_raw_ptr(range); - - /* check for if #initialize_copy was removed [#3320] */ - if (!RANGE_INITIALIZED_P(r)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); - } - return r; -} - static void -range_check(mrb_state *mrb, mrb_value a, mrb_value b) +r_check(mrb_state *mrb, mrb_value a, mrb_value b) { mrb_value ans; enum mrb_vtype ta; @@ -51,6 +39,43 @@ range_check(mrb_state *mrb, mrb_value a, mrb_value b) } } +static mrb_bool +r_le(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == -1) return TRUE; + } + + return FALSE; +} + +static mrb_bool +r_gt(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; +} + +static mrb_bool +r_ge(mrb_state *mrb, mrb_value a, mrb_value b) +{ + mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ + /* output :a < b => -1, a = b => 0, a > b => +1 */ + + if (mrb_fixnum_p(r)) { + mrb_int c = mrb_fixnum(r); + if (c == 0 || c == 1) return TRUE; + } + + return FALSE; +} + static void range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) { @@ -62,7 +87,7 @@ range_ptr_alloc_edges(mrb_state *mrb, struct RRange *r) static struct RRange * range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, mrb_bool excl) { - range_check(mrb, beg, end); + r_check(mrb, beg, end); if (r) { if (RANGE_INITIALIZED_P(r)) { @@ -93,13 +118,6 @@ range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end mrb_write_barrier(mrb, (struct RBasic*)r); } -MRB_API mrb_value -mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) -{ - struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); - return mrb_range_value(r); -} - /* * call-seq: * rng.first => obj @@ -123,7 +141,6 @@ range_beg(mrb_state *mrb, mrb_value range) * (1..10).end #=> 10 * (1...10).end #=> 10 */ - static mrb_value range_end(mrb_state *mrb, mrb_value range) { @@ -136,8 +153,8 @@ range_end(mrb_state *mrb, mrb_value range) * * Returns true if range excludes its end value. */ -mrb_value -mrb_range_excl(mrb_state *mrb, mrb_value range) +static mrb_value +range_excl(mrb_state *mrb, mrb_value range) { return mrb_bool_value(mrb_range_excl_p(mrb, range)); } @@ -150,21 +167,18 @@ mrb_range_excl(mrb_state *mrb, mrb_value range) * parameter is omitted or is false, the range will include * the end object; otherwise, it will be excluded. */ - -mrb_value -mrb_range_initialize(mrb_state *mrb, mrb_value range) +static mrb_value +range_initialize(mrb_state *mrb, mrb_value range) { mrb_value beg, end; - mrb_bool exclusive; + mrb_bool exclusive = FALSE; mrb_int n; n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); - if (n != 3) { - exclusive = FALSE; - } range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } + /* * call-seq: * range == obj => true or false @@ -177,11 +191,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) * (0..2) == (0..2) #=> true * (0..2) == Range.new(0,2) #=> true * (0..2) == (0...2) #=> false - * */ - -mrb_value -mrb_range_eq(mrb_state *mrb, mrb_value range) +static mrb_value +range_eq(mrb_state *mrb, mrb_value range) { struct RRange *rr; struct RRange *ro; @@ -204,52 +216,14 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) return mrb_true_value(); } -static mrb_bool -r_le(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - if (mrb_fixnum_p(r)) { - mrb_int c = mrb_fixnum(r); - if (c == 0 || c == -1) return TRUE; - } - - return FALSE; -} - -static mrb_bool -r_gt(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - return mrb_fixnum_p(r) && mrb_fixnum(r) == 1; -} - -static mrb_bool -r_ge(mrb_state *mrb, mrb_value a, mrb_value b) -{ - mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */ - /* output :a < b => -1, a = b => 0, a > b => +1 */ - - if (mrb_fixnum_p(r)) { - mrb_int c = mrb_fixnum(r); - if (c == 0 || c == 1) return TRUE; - } - - return FALSE; -} - /* * call-seq: * range === obj => true or false * range.member?(val) => true or false * range.include?(val) => true or false - * */ -mrb_value -mrb_range_include(mrb_state *mrb, mrb_value range) +static mrb_value +range_include(mrb_state *mrb, mrb_value range) { mrb_value val; struct RRange *r = mrb_range_ptr(mrb, range); @@ -267,39 +241,6 @@ mrb_range_include(mrb_state *mrb, mrb_value range) return mrb_bool_value(include_p); } -MRB_API mrb_int -mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) -{ - mrb_int beg, end; - struct RRange *r; - - if (mrb_type(range) != MRB_TT_RANGE) return 0; - r = mrb_range_ptr(mrb, range); - - beg = mrb_int(mrb, RANGE_BEG(r)); - end = mrb_int(mrb, RANGE_END(r)); - - if (beg < 0) { - beg += len; - if (beg < 0) return 2; - } - - if (trunc) { - if (beg > len) return 2; - if (end > len) end = len; - } - - if (end < 0) end += len; - if (!RANGE_EXCL(r) && (!trunc || end < len)) - end++; /* include end point */ - len = end - beg; - if (len < 0) len = 0; - - *begp = beg; - *lenp = len; - return 1; -} - /* 15.2.14.4.12(x) */ /* * call-seq: @@ -307,7 +248,6 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, * * Convert this range object to a printable form. */ - static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { @@ -332,7 +272,6 @@ range_to_s(mrb_state *mrb, mrb_value range) * inspect to convert the start and end * objects). */ - static mrb_value range_inspect(mrb_state *mrb, mrb_value range) { @@ -360,9 +299,7 @@ range_inspect(mrb_state *mrb, mrb_value range) * (0..2).eql?(0..2) #=> true * (0..2).eql?(Range.new(0,2)) #=> true * (0..2).eql?(0...2) #=> false - * */ - static mrb_value range_eql(mrb_state *mrb, mrb_value range) { @@ -372,9 +309,7 @@ range_eql(mrb_state *mrb, mrb_value range) mrb_get_args(mrb, "o", &obj); if (mrb_obj_equal(mrb, range, obj)) return mrb_true_value(); - if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) { - return mrb_false_value(); - } + if (!mrb_obj_is_kind_of(mrb, obj, mrb->range_class)) return mrb_false_value(); if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); r = mrb_range_ptr(mrb, range); @@ -445,6 +380,57 @@ mrb_gc_mark_range(mrb_state *mrb, struct RRange *r) } } +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value range) +{ + struct RRange *r = mrb_range_raw_ptr(range); + + /* check for if #initialize_copy was removed [#3320] */ + if (!RANGE_INITIALIZED_P(r)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + +MRB_API mrb_value +mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) +{ + struct RRange *r = range_ptr_init(mrb, NULL, beg, end, excl); + return mrb_range_value(r); +} + +MRB_API mrb_int +mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) +{ + mrb_int beg, end; + struct RRange *r; + + if (mrb_type(range) != MRB_TT_RANGE) return 0; + r = mrb_range_ptr(mrb, range); + + beg = mrb_int(mrb, RANGE_BEG(r)); + end = mrb_int(mrb, RANGE_END(r)); + + if (beg < 0) { + beg += len; + if (beg < 0) return 2; + } + + if (trunc) { + if (beg > len) return 2; + if (end > len) end = len; + } + + if (end < 0) end += len; + if (!RANGE_EXCL(r) && (!trunc || end < len)) end++; /* include end point */ + len = end - beg; + if (len < 0) len = 0; + + *begp = beg; + *lenp = len; + return 1; +} + void mrb_init_range(mrb_state *mrb) { @@ -456,15 +442,14 @@ mrb_init_range(mrb_state *mrb) mrb_define_method(mrb, r, "begin", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */ mrb_define_method(mrb, r, "end", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */ - mrb_define_method(mrb, r, "==", mrb_range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ - mrb_define_method(mrb, r, "===", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ - mrb_define_method(mrb, r, "exclude_end?", mrb_range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ + mrb_define_method(mrb, r, "==", range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */ + mrb_define_method(mrb, r, "===", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */ + mrb_define_method(mrb, r, "exclude_end?", range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */ mrb_define_method(mrb, r, "first", range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */ - mrb_define_method(mrb, r, "include?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ - mrb_define_method(mrb, r, "initialize", mrb_range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ + mrb_define_method(mrb, r, "include?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */ + mrb_define_method(mrb, r, "initialize", range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */ mrb_define_method(mrb, r, "last", range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */ - mrb_define_method(mrb, r, "member?", mrb_range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ - + mrb_define_method(mrb, r, "member?", range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */ mrb_define_method(mrb, r, "to_s", range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */ mrb_define_method(mrb, r, "inspect", range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */ mrb_define_method(mrb, r, "eql?", range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */ -- cgit v1.2.3 From 53d87c59c077238be261aad98ed720aebf6402d1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 4 Jan 2019 14:40:58 +0900 Subject: Remove unused local variable `n` in `range_initialize`; #4213 --- src/range.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/range.c b/src/range.c index 2f2521f5e..21771c8ec 100644 --- a/src/range.c +++ b/src/range.c @@ -172,9 +172,8 @@ range_initialize(mrb_state *mrb, mrb_value range) { mrb_value beg, end; mrb_bool exclusive = FALSE; - mrb_int n; - n = mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); + mrb_get_args(mrb, "oo|b", &beg, &end, &exclusive); range_ptr_replace(mrb, mrb_range_raw_ptr(range), beg, end, exclusive); return range; } -- cgit v1.2.3 From b30ca87bd07a29a2dddc4960ce80f767ff9552ca Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 4 Jan 2019 20:31:05 +0900 Subject: Integrate mrblib/float.rb into src/numeric.c - Avoid hack for `MRB_WITHOUT_FLOAT` in build scripts - Avoid runtime dispatch for `MRB_WITHOUT_FLOAT` --- mrblib/float.rb | 9 --------- mrblib/mrblib.rake | 3 --- src/numeric.c | 7 +++++-- 3 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 mrblib/float.rb (limited to 'src') diff --git a/mrblib/float.rb b/mrblib/float.rb deleted file mode 100644 index 421b8d851..000000000 --- a/mrblib/float.rb +++ /dev/null @@ -1,9 +0,0 @@ -## -# Float -# -# ISO 15.2.9 -class Float - # mruby special - since mruby integers may be upgraded to floats, - # floats should be compatible to integers. - include Integral -end if Object.const_defined?(:Float) diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake index 6895d4252..e96decb27 100644 --- a/mrblib/mrblib.rake +++ b/mrblib/mrblib.rake @@ -8,9 +8,6 @@ MRuby.each_target do file objfile("#{current_build_dir}/mrblib") => "#{current_build_dir}/mrblib.c" file "#{current_build_dir}/mrblib.c" => [mrbcfile, __FILE__] + Dir.glob("#{current_dir}/*.rb").sort do |t| _, _, *rbfiles = t.prerequisites - if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") - rbfiles.delete("#{current_dir}/float.rb") - end FileUtils.mkdir_p File.dirname(t.name) open(t.name, 'w') do |f| _pp "GEN", "*.rb", "#{t.name.relative_path}" diff --git a/src/numeric.c b/src/numeric.c index 077ae30aa..311bb4a38 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1487,11 +1487,13 @@ flo_plus(mrb_state *mrb, mrb_value x) void mrb_init_numeric(mrb_state *mrb) { - struct RClass *numeric, *integer, *fixnum; + struct RClass *numeric, *integer, *fixnum, *integral; #ifndef MRB_WITHOUT_FLOAT struct RClass *fl; #endif + integral = mrb_define_module(mrb, "Integral"); + /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ @@ -1578,6 +1580,7 @@ mrb_init_numeric(mrb_state *mrb) #ifdef NAN mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN)); #endif + + mrb_include_module(mrb, fl, integral); #endif - mrb_define_module(mrb, "Integral"); } -- cgit v1.2.3 From 68735d12614ef72b620736a5cd3052fb79445483 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 8 Jan 2019 20:31:29 +0900 Subject: Fix dump/load float leteral evaluate to infinity Example: # example.rb p(2e308) p(-2e308) Good: $ bin/mruby example.rb inf -inf Bad: $ bin/mrbc example.rb $ bin/mruby -b example.mrb 0 -0 Cause: Float infinity representation is `inf` on dump and it is converted by corresponding `String#to_f` on load. Treatment: - Introduce new representations (`i`: +infinity, `I`: -infinity) - Allow old representations (`inf`, `-inf`, `infinity`, `-infinity`) too - Raise error for unknown representations (use corresponding `Kernel#Float`) --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 7 +++++++ src/dump.c | 17 +++++++++++++++-- src/load.c | 20 +++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index a7fb63fa2..f3c7d8761 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -31,6 +31,13 @@ assert '$0 value' do assert_equal '"-e"', `#{cmd('mruby')} -e #{shellquote('p $0')}`.chomp end +assert('float literal') do + script, bin = Tempfile.new('test.rb'), Tempfile.new('test.mrb') + File.write script.path, 'p [3.21, 2e308.infinite?, -2e308.infinite?]' + system "#{cmd('mrbc')} -g -o #{bin.path} #{script.path}" + assert_equal "[3.21, 1, -1]", `#{cmd('mruby')} -b #{bin.path}`.chomp! +end + assert '__END__', '8.6' do script = Tempfile.new('test.rb') diff --git a/src/dump.c b/src/dump.c index 6ce9c4eb9..11eba4e40 100644 --- a/src/dump.c +++ b/src/dump.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -90,6 +91,18 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) return cur - buf; } +#ifndef MRB_WITHOUT_FLOAT +static mrb_value +float_to_str(mrb_state *mrb, mrb_value flt) +{ + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "I") : mrb_str_new_lit(mrb, "i"); + } + return mrb_float_to_str(mrb, flt, MRB_FLOAT_FMT); +} +#endif static size_t get_pool_block_size(mrb_state *mrb, mrb_irep *irep) @@ -116,7 +129,7 @@ get_pool_block_size(mrb_state *mrb, mrb_irep *irep) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: - str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + str = float_to_str(mrb, irep->pool[pool_no]); { mrb_int len = RSTRING_LEN(str); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); @@ -165,7 +178,7 @@ write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf) #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */ - str = mrb_float_to_str(mrb, irep->pool[pool_no], MRB_FLOAT_FMT); + str = float_to_str(mrb, irep->pool[pool_no]); break; #endif diff --git a/src/load.c b/src/load.c index 559fff1d4..55e0845f3 100644 --- a/src/load.c +++ b/src/load.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,23 @@ offset_crc_body(void) return ((uint8_t *)header.binary_crc - (uint8_t *)&header) + sizeof(header.binary_crc); } +#ifndef MRB_WITHOUT_FLOAT +static double +str_to_double(mrb_state *mrb, mrb_value str) +{ + const char *p = RSTRING_PTR(str); + mrb_int len = RSTRING_LEN(str); + + /* `i`, `inf`, `infinity` */ + if (len > 0 && p[0] == 'i') return INFINITY; + + /* `I`, `-inf`, `-infinity` */ + if (p[0] == 'I' || (len > 1 && p[0] == '-' && p[1] == 'i')) return -INFINITY; + + return mrb_str_to_dbl(mrb, str, TRUE); +} +#endif + static mrb_irep* read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags) { @@ -125,7 +143,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag #ifndef MRB_WITHOUT_FLOAT case IREP_TT_FLOAT: - irep->pool[i] = mrb_float_pool(mrb, mrb_str_to_dbl(mrb, s, FALSE)); + irep->pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s)); break; #endif -- cgit v1.2.3 From 856b8d961015d67eb7b4958eb974bbfabbc1066a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 10 Jan 2019 23:22:23 +0900 Subject: Remove duplicate code in numeric.c --- src/numeric.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 311bb4a38..089cc744d 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1150,7 +1150,7 @@ fix_to_f(mrb_state *mrb, mrb_value num) * (in particular infinite or NaN) * to numerical classes which don't support them. * - * Float::INFINITY.to_r + * Float::INFINITY.to_i * * raises the exception: * @@ -1169,12 +1169,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) else { mrb_float d = mrb_float(x); - if (isinf(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity"); - } - if (isnan(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); - } + mrb_check_num_exact(mrb, d); if (FIXABLE_FLOAT(d)) { z = (mrb_int)d; } -- cgit v1.2.3 From 2d8aec2b8833065695f7e0fe42f70e0b5610afce Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 11 Jan 2019 19:54:46 +0900 Subject: Use `%g` instead of `%e` for float representation in dump format `%g` use shorter representation than `%e`. --- src/dump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/dump.c b/src/dump.c index 11eba4e40..f1e167e35 100644 --- a/src/dump.c +++ b/src/dump.c @@ -18,9 +18,9 @@ #ifndef MRB_WITHOUT_FLOAT #ifdef MRB_USE_FLOAT -#define MRB_FLOAT_FMT "%.8e" +#define MRB_FLOAT_FMT "%.9g" #else -#define MRB_FLOAT_FMT "%.16e" +#define MRB_FLOAT_FMT "%.17g" #endif #endif -- cgit v1.2.3 From 9f081183d2351195c821fbe1520975ba000cafb5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 13 Jan 2019 19:59:22 +0900 Subject: Improve compatibility to CRuby for `Float#to_s` Bfore: Float::INFINITY.to_s #=> "inf" 50.0.to_s #=> "50" 1e20.to_s #=> "1e+20" After / CRuby: Float::INFINITY.to_s #=> "Infinity" 50.0.to_s #=> "50.0" 1e20.to_s #=> "1.0e+20" --- src/numeric.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- test/t/float.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 089cc744d..fc8460300 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -10,6 +10,7 @@ #endif #include #include +#include #include #include @@ -23,9 +24,9 @@ #define floor(f) floorf(f) #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) -#define MRB_FLO_TO_STR_FMT "%.8g" +#define FLO_TO_STR_PREC 8 #else -#define MRB_FLO_TO_STR_FMT "%.16g" +#define FLO_TO_STR_PREC 16 #endif #endif @@ -177,10 +178,49 @@ num_div(mrb_state *mrb, mrb_value x) static mrb_value flo_to_s(mrb_state *mrb, mrb_value flt) { - if (isnan(mrb_float(flt))) { + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "-Infinity") + : mrb_str_new_lit(mrb, "Infinity"); + } + else if (isnan(f)) { return mrb_str_new_lit(mrb, "NaN"); } - return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT); + else { + char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; + mrb_value str = mrb_float_to_str(mrb, flt, fmt); + mrb_int len; + char *begp; + + insert_dot_zero: + begp = RSTRING_PTR(str); + len = RSTRING_LEN(str); + for (char *p = begp, *endp = p + len; p < endp; ++p) { + if (*p == '.') { + return str; + } + else if (*p == 'e') { + ptrdiff_t e_pos = p - begp; + mrb_str_cat(mrb, str, ".0", 2); + p = RSTRING_PTR(str) + e_pos; + memmove(p + 2, p, len - e_pos); + memcpy(p, ".0", 2); + return str; + } + } + + if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) { + --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */ + str = mrb_float_to_str(mrb, flt, fmt); + goto insert_dot_zero; + } + else { + mrb_str_cat(mrb, str, ".0", 2); + } + + return str; + } } /* 15.2.9.3.2 */ diff --git a/test/t/float.rb b/test/t/float.rb index 68fd31b9a..eac5c5792 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -206,4 +206,37 @@ assert('Float#>>') do assert_equal(-1, -23.0 >> 128) end +assert('Float#to_s') do + uses_float = 4e38.infinite? # enable MRB_USE_FLOAT? + + assert_equal("Infinity", Float::INFINITY.to_s) + assert_equal("-Infinity", (-Float::INFINITY).to_s) + assert_equal("NaN", Float::NAN.to_s) + assert_equal("0.0", 0.0.to_s) + assert_equal("-0.0", -0.0.to_s) + assert_equal("-3.21", -3.21.to_s) + assert_equal("50.0", 50.0.to_s) + assert_equal("0.00021", 0.00021.to_s) + assert_equal("-0.00021", -0.00021.to_s) + assert_equal("2.1e-05", 0.000021.to_s) + assert_equal("-2.1e-05", -0.000021.to_s) + assert_equal("1.0e+20", 1e20.to_s) + assert_equal("-1.0e+20", -1e20.to_s) + assert_equal("1.0e+16", 10000000000000000.0.to_s) + assert_equal("-1.0e+16", -10000000000000000.0.to_s) + assert_equal("100000.0", 100000.0.to_s) + assert_equal("-100000.0", -100000.0.to_s) + if uses_float + assert_equal("1.0e+08", 100000000.0.to_s) + assert_equal("-1.0e+08", -100000000.0.to_s) + assert_equal("1.0e+07", 10000000.0.to_s) + assert_equal("-1.0e+07", -10000000.0.to_s) + else + assert_equal("1.0e+15", 1000000000000000.0.to_s) + assert_equal("-1.0e+15", -1000000000000000.0.to_s) + assert_equal("100000000000000.0", 100000000000000.0.to_s) + assert_equal("-100000000000000.0", -100000000000000.0.to_s) + end +end + end # const_defined?(:Float) -- cgit v1.2.3 From 0e04c46261eb9d5193f21d423f5d00f1910a460a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 13 Jan 2019 23:24:57 +0900 Subject: Use 2 digits exponent format for `printf` family on old MSVC For conforming C standard. --- src/state.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/state.c b/src/state.c index 5583a77e5..e678b37f3 100644 --- a/src/state.c +++ b/src/state.c @@ -41,6 +41,10 @@ mrb_open_core(mrb_allocf f, void *ud) mrb_init_core(mrb); +#if !defined(MRB_DISABLE_STDIO) && defined(_MSC_VER) && _MSC_VER < 1900 + _set_output_format(_TWO_DIGIT_EXPONENT); +#endif + return mrb; } -- cgit v1.2.3 From 8969edf03b2f4ff8537974c2bd30e9abe2002da6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 16 Jan 2019 19:32:29 +0900 Subject: Avoid runtime evaluation for `MRB_WITHOUT_FLOAT` --- mrblib/numeric.rb | 9 +-------- src/numeric.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index dfdaf9da8..5a3c5eb58 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -104,14 +104,7 @@ module Integral raise ArgumentError, "step can't be 0" if step == 0 return to_enum(:step, num, step) unless block - i = self - if Object.const_defined?(:Float) && - (kind_of?(Float) || num.kind_of?(Float) || step.kind_of?(Float)) - i = i.to_f - num = num.to_f unless num == nil - step = step.to_f - end - + i = __coerce_step_counter(num, step) if num == nil while true block.call(i) diff --git a/src/numeric.c b/src/numeric.c index fc8460300..fa9daf8a7 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -154,6 +154,22 @@ num_div(mrb_state *mrb, mrb_value x) #endif } +static mrb_value +num_coerce_step_counter(mrb_state *mrb, mrb_value self) +{ + mrb_value counter = self, num, step; + + mrb_get_args(mrb, "oo", &num, &step); + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { + counter = mrb_funcall(mrb, counter, "to_f", 0); + } +#endif + + return counter; +} + #ifndef MRB_WITHOUT_FLOAT /******************************************************************** * @@ -1542,6 +1558,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2)); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ -- cgit v1.2.3 From 366a14f297a6b31301b8e01f5ef21ad8fe184977 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 16 Jan 2019 23:48:59 +0900 Subject: Remove special treatments for `MRB_WITHOUT_FLOAT` in build scripts --- mrbgems/mruby-test/mrbgem.rake | 4 ---- src/mruby_core.rake | 1 - 2 files changed, 5 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 6f94da92d..61bdf9ced 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -7,10 +7,6 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| spec.add_dependency('mruby-compiler', :core => 'mruby-compiler') spec.test_rbfiles = Dir.glob("#{MRUBY_ROOT}/test/t/*.rb") - if build.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") - spec.test_rbfiles.delete("#{MRUBY_ROOT}/test/t/float.rb") - end - clib = "#{build_dir}/mrbtest.c" mlib = clib.ext(exts.object) diff --git a/src/mruby_core.rake b/src/mruby_core.rake index 3024c8544..73fddb220 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -5,7 +5,6 @@ MRuby.each_target do objs = Dir.glob("#{current_dir}/*.c").map { |f| next nil if cxx_exception_enabled? and f =~ /(error|vm).c$/ - next nil if self.cc.defines.flatten.include?("MRB_WITHOUT_FLOAT") and f =~ /fmt_fp.c$/ objfile(f.pathmap("#{current_build_dir}/%n")) }.compact -- cgit v1.2.3 From dff0f2ee10c93a12fcc9cea1eb6b2c57667ee5de Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 19 Jan 2019 20:40:21 +0900 Subject: Remove `.gitkeep` files --- bin/.gitkeep | 0 src/ext/.gitkeep | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bin/.gitkeep delete mode 100644 src/ext/.gitkeep (limited to 'src') diff --git a/bin/.gitkeep b/bin/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/ext/.gitkeep b/src/ext/.gitkeep deleted file mode 100644 index e69de29bb..000000000 -- cgit v1.2.3 From 486154ce34580620a27cd2da506994248e830ca2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 29 Jan 2019 20:21:25 +0900 Subject: Remove unused macro in `src/string.c` --- src/string.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 52941473c..52b869eca 100644 --- a/src/string.c +++ b/src/string.c @@ -1587,8 +1587,6 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) return mrb_fixnum_value(pos); } -#define STR_REPLACE_SHARED_MIN 10 - /* 15.2.10.5.24 */ /* 15.2.10.5.28 */ /* -- cgit v1.2.3 From 69fd1a592560d321061790c94f93532db93dccb9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 4 Feb 2019 18:11:22 +0900 Subject: Fix `Symbol#size` for multi-byte characters with `MRB_UTF8_STRING` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: p :あ.size #=> 3 After: p :あ.size #=> 1 --- include/mruby/string.h | 4 ++++ mrbgems/mruby-symbol-ext/src/symbol.c | 7 +++++++ mrbgems/mruby-symbol-ext/test/symbol.rb | 15 +++++++++++--- src/string.c | 35 +++++++++++++++++++++------------ 4 files changed, 45 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/include/mruby/string.h b/include/mruby/string.h index 3fe8295ff..6fe0556b0 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -439,6 +439,10 @@ void mrb_regexp_check(mrb_state *mrb, mrb_value obj); #define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) #define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2) +#ifdef MRB_UTF8_STRING +mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); +#endif + MRB_END_DECL #endif /* MRUBY_STRING_H */ diff --git a/mrbgems/mruby-symbol-ext/src/symbol.c b/mrbgems/mruby-symbol-ext/src/symbol.c index a992dbfce..215226502 100644 --- a/mrbgems/mruby-symbol-ext/src/symbol.c +++ b/mrbgems/mruby-symbol-ext/src/symbol.c @@ -1,6 +1,7 @@ #include #include #include +#include typedef struct symbol_name { size_t len; @@ -45,7 +46,13 @@ static mrb_value mrb_sym_length(mrb_state *mrb, mrb_value self) { mrb_int len; +#ifdef MRB_UTF8_STRING + mrb_int byte_len; + const char *name = mrb_sym2name_len(mrb, mrb_symbol(self), &byte_len); + len = mrb_utf8_len(name, byte_len); +#else mrb_sym2name_len(mrb, mrb_symbol(self), &len); +#endif return mrb_fixnum_value(len); } diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb index 63c1bd826..2c7a62b0c 100644 --- a/mrbgems/mruby-symbol-ext/test/symbol.rb +++ b/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -7,9 +7,18 @@ assert('Symbol.all_symbols') do assert_equal foo, symbols end -assert("Symbol#length") do - assert_equal 5, :hello.size - assert_equal 5, :mruby.length +%w[size length].each do |n| + assert("Symbol##{n}") do + assert_equal 5, :hello.__send__(n) + assert_equal 4, :"aA\0b".__send__(n) + if "あ".size == 1 # enable MRB_UTF8_STRING? + assert_equal 8, :"こんにちは世界!".__send__(n) + assert_equal 4, :"aあ\0b".__send__(n) + else + assert_equal 22, :"こんにちは世界!".__send__(n) + assert_equal 6, :"aあ\0b".__send__(n) + end + end end assert("Symbol#capitalize") do diff --git a/src/string.c b/src/string.c index 52b869eca..148e2fee2 100644 --- a/src/string.c +++ b/src/string.c @@ -238,27 +238,36 @@ utf8len(const char* p, const char* e) return len; } -static mrb_int -utf8_strlen(mrb_value str, mrb_int len) +mrb_int +mrb_utf8_len(const char *str, mrb_int byte_len) { mrb_int total = 0; - char* p = RSTRING_PTR(str); - char* e = p; - if (RSTRING(str)->flags & MRB_STR_NO_UTF) { - return RSTRING_LEN(str); - } - e += len < 0 ? RSTRING_LEN(str) : len; - while (pflags |= MRB_STR_NO_UTF; - } return total; } -#define RSTRING_CHAR_LEN(s) utf8_strlen(s, -1) +static mrb_int +utf8_strlen(mrb_value str) +{ + mrb_int byte_len = RSTRING_LEN(str); + + if (RSTRING(str)->flags & MRB_STR_NO_UTF) { + return byte_len; + } + else { + mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); + if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_NO_UTF; + return utf8_len; + } +} + +#define RSTRING_CHAR_LEN(s) utf8_strlen(s) /* map character index to byte offset index */ static mrb_int -- cgit v1.2.3 From 7a2865cfef443e28cd377f359b1a3c98b101c517 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 5 Feb 2019 19:08:53 +0900 Subject: Fix markup and remove unneeded comment for doc in `src/string.c` [ci skip] --- src/string.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 148e2fee2..d26d6f4c9 100644 --- a/src/string.c +++ b/src/string.c @@ -156,13 +156,6 @@ mrb_str_new(mrb_state *mrb, const char *p, size_t len) return mrb_obj_value(str_new(mrb, p, len)); } -/* - * call-seq: (Caution! NULL string) - * String.new(str="") => new_str - * - * Returns a new string object containing a copy of str. - */ - MRB_API mrb_value mrb_str_new_cstr(mrb_state *mrb, const char *p) { @@ -748,12 +741,6 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) return RSTR_PTR(s); } -/* - * call-seq: (Caution! String("abcd") change) - * String("abcdefg") = String("abcd") + String("efg") - * - * Returns a new string object containing a copy of str. - */ MRB_API void mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) { @@ -761,12 +748,6 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) mrb_str_cat_str(mrb, self, other); } -/* - * call-seq: (Caution! String("abcd") remain) - * String("abcdefg") = String("abcd") + String("efg") - * - * Returns a new string object containing a copy of str. - */ MRB_API mrb_value mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) { @@ -784,10 +765,13 @@ mrb_str_plus(mrb_state *mrb, mrb_value a, mrb_value b) /* 15.2.10.5.2 */ /* - * call-seq: (Caution! String("abcd") remain) for stack_argument - * String("abcdefg") = String("abcd") + String("efg") + * call-seq: + * str + other_str -> new_str * - * Returns a new string object containing a copy of str. + * Concatenation---Returns a new String containing + * other_str concatenated to str. + * + * "Hello from " + self.to_s #=> "Hello from main" */ static mrb_value mrb_str_plus_m(mrb_state *mrb, mrb_value self) -- cgit v1.2.3 From 5ef1e479da7e1864067092ed87f83f85120c8324 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 5 Feb 2019 19:15:52 +0900 Subject: Remove old comment for `mrb_sym2name_len()` [ci skip] --- src/symbol.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 6b4c7200c..bed918241 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -143,7 +143,6 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); } -/* lenp must be a pointer to a size_t variable */ MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { -- cgit v1.2.3 From 02fbb2c21134ad0e8df0b723a4b11f7d7e21edcd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 Jan 2019 17:57:12 +0900 Subject: Remove symbol hash table from `mrb_state` structure. Use linear search instead. Number of symbols is usually small (<1K), so we don't need performance boost from hash tables. In our benchmark measurement, hash tables consumes 790KB for `build/full-debug/mrbtest`. --- include/mruby.h | 1 - src/symbol.c | 69 ++++++++++++++++++++------------------------------------- 2 files changed, 24 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 8c8360784..7fe2330be 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -239,7 +239,6 @@ typedef struct mrb_state { #endif mrb_sym symidx; - struct kh_n2s *name2sym; /* symbol hash */ struct symbol_name *symtbl; /* symbol table */ size_t symcapa; diff --git a/src/symbol.c b/src/symbol.c index bed918241..bebbb8e85 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -19,24 +19,6 @@ typedef struct symbol_name { const char *name; } symbol_name; -static inline khint_t -sym_hash_func(mrb_state *mrb, mrb_sym s) -{ - khint_t h = 0; - size_t i, len = mrb->symtbl[s].len; - const char *p = mrb->symtbl[s].name; - - for (i=0; isymtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0) - -KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE) -KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal) -/* ------------------------------------------------------ */ - static void sym_validate_len(mrb_state *mrb, size_t len) { @@ -45,24 +27,31 @@ sym_validate_len(mrb_state *mrb, size_t len) } } +static mrb_sym +find_symbol(mrb_state *mrb, const char *name, uint16_t len) +{ + mrb_sym i; + symbol_name *sname; + + /* search for a symbol */ + for (i=1; i<=mrb->symidx; i++) { + sname = &mrb->symtbl[i]; + if (sname->len == len && memcmp(sname->name, name, len) == 0) { + return i; + } + } + return 0; +} + static mrb_sym sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) { - khash_t(n2s) *h = mrb->name2sym; - symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */ - khiter_t k; mrb_sym sym; - char *p; + symbol_name *sname; sym_validate_len(mrb, len); - if (sname) { - sname->lit = lit; - sname->len = (uint16_t)len; - sname->name = name; - k = kh_get(n2s, mrb, h, 0); - if (k != kh_end(h)) - return kh_key(h, k); - } + sym = find_symbol(mrb, name, len); + if (sym > 0) return sym; /* registering a new symbol */ sym = ++mrb->symidx; @@ -78,13 +67,12 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) sname->lit = TRUE; } else { - p = (char *)mrb_malloc(mrb, len+1); + char *p = (char *)mrb_malloc(mrb, len+1); memcpy(p, name, len); p[len] = 0; sname->name = (const char*)p; sname->lit = FALSE; } - kh_put(n2s, mrb, h, sym); return sym; } @@ -116,25 +104,18 @@ mrb_intern_str(mrb_state *mrb, mrb_value str) MRB_API mrb_value mrb_check_intern(mrb_state *mrb, const char *name, size_t len) { - khash_t(n2s) *h = mrb->name2sym; - symbol_name *sname = mrb->symtbl; - khiter_t k; + mrb_sym sym; sym_validate_len(mrb, len); - sname->len = (uint16_t)len; - sname->name = name; - - k = kh_get(n2s, mrb, h, 0); - if (k != kh_end(h)) { - return mrb_symbol_value(kh_key(h, k)); - } + sym = find_symbol(mrb, name, len); + if (sym > 0) return mrb_symbol_value(sym); return mrb_nil_value(); } MRB_API mrb_value mrb_check_intern_cstr(mrb_state *mrb, const char *name) { - return mrb_check_intern(mrb, name, (mrb_int)strlen(name)); + return mrb_check_intern(mrb, name, strlen(name)); } MRB_API mrb_value @@ -166,13 +147,11 @@ mrb_free_symtbl(mrb_state *mrb) } } mrb_free(mrb, mrb->symtbl); - kh_destroy(n2s, mrb, mrb->name2sym); } void mrb_init_symtbl(mrb_state *mrb) { - mrb->name2sym = kh_init(n2s, mrb); } /********************************************************************** -- cgit v1.2.3 From 905fef2669f4dd0efb71205219872d9fb4b135b6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 5 Feb 2019 14:20:58 +0900 Subject: Reduce invocation of `mrb_convert_type()` from `mrb_str_to_str()`. --- src/class.c | 2 +- src/string.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index dd5b65cc3..359bb4fea 100644 --- a/src/class.c +++ b/src/class.c @@ -1815,7 +1815,7 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const * show information on the thing we're attached to as well. */ -static mrb_value +mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { mrb_value str; diff --git a/src/string.c b/src/string.c index d26d6f4c9..19962fb30 100644 --- a/src/string.c +++ b/src/string.c @@ -20,6 +20,7 @@ #include #include #include +#include #include typedef struct mrb_shared_string { @@ -972,13 +973,22 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1) return mrb_bool_value(mrb_str_equal(mrb, str1, str2)); } /* ---------------------------------- */ +mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass); + MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str) { - if (!mrb_string_p(str)) { + switch (mrb_type(str)) { + case MRB_TT_STRING: + return str; + case MRB_TT_FIXNUM: + return mrb_fixnum_to_str(mrb, str, 10); + case MRB_TT_CLASS: + case MRB_TT_MODULE: + return mrb_mod_to_s(mrb, str); + default: return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); } - return str; } MRB_API const char* -- cgit v1.2.3 From d52f46da4571c7c44954b15f85a00d74ab86f7f3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 5 Feb 2019 17:27:24 +0900 Subject: Implement symbol hash table to boost `find_symbol`. In 4174e02, we removed the symbol hash table from `mrb_state` but `find_symbol` was too slow with linear search. My performance estimation was wrong. So we implemented a new compact hash table for symbols. --- include/mruby.h | 1 + src/symbol.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 7fe2330be..2f2d98677 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -240,6 +240,7 @@ typedef struct mrb_state { mrb_sym symidx; struct symbol_name *symtbl; /* symbol table */ + mrb_sym symhash[256]; size_t symcapa; #ifdef MRB_ENABLE_DEBUG_HOOK diff --git a/src/symbol.c b/src/symbol.c index bebbb8e85..4242f3d8e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -15,6 +15,7 @@ /* ------------------------------------------------------ */ typedef struct symbol_name { mrb_bool lit : 1; + uint8_t prev; uint16_t len; const char *name; } symbol_name; @@ -27,19 +28,48 @@ sym_validate_len(mrb_state *mrb, size_t len) } } +uint8_t +symhash(const char *key, size_t len) +{ + uint32_t hash, i; + + for(hash = i = 0; i < len; ++i) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash & 0xff; +} + static mrb_sym -find_symbol(mrb_state *mrb, const char *name, uint16_t len) +find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) { mrb_sym i; symbol_name *sname; - /* search for a symbol */ - for (i=1; i<=mrb->symidx; i++) { + i = mrb->symhash[hash]; + if (i == 0) return 0; + do { sname = &mrb->symtbl[i]; if (sname->len == len && memcmp(sname->name, name, len) == 0) { return i; } - } + if (sname->prev == 0xff) { + i -= 0xff; + sname = &mrb->symtbl[i]; + while (mrb->symtbl < sname) { + if (sname->len == len && memcmp(sname->name, name, len) == 0) { + return (mrb_sym)(sname - mrb->symtbl); + } + sname--; + } + return 0; + } + i -= sname->prev; + } while (sname->prev > 0); return 0; } @@ -48,9 +78,11 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) { mrb_sym sym; symbol_name *sname; + uint8_t hash; sym_validate_len(mrb, len); - sym = find_symbol(mrb, name, len); + hash = symhash(name, len); + sym = find_symbol(mrb, name, len, hash); if (sym > 0) return sym; /* registering a new symbol */ @@ -73,6 +105,17 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) sname->name = (const char*)p; sname->lit = FALSE; } + if (mrb->symhash[hash]) { + mrb_sym i = sym - mrb->symhash[hash]; + if (i > 0xff) + sname->prev = 0xff; + else + sname->prev = i; + } + else { + sname->prev = 0; + } + mrb->symhash[hash] = sym; return sym; } @@ -107,7 +150,7 @@ mrb_check_intern(mrb_state *mrb, const char *name, size_t len) mrb_sym sym; sym_validate_len(mrb, len); - sym = find_symbol(mrb, name, len); + sym = find_symbol(mrb, name, len, symhash(name, len)); if (sym > 0) return mrb_symbol_value(sym); return mrb_nil_value(); } -- cgit v1.2.3 From eb6aee117b8f33810a285a248cf21d2e2409823a Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 9 Feb 2019 20:22:08 +0900 Subject: `mrb_default_allocf()` is default allocator for NULL safe --- src/state.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/state.c b/src/state.c index e678b37f3..c3ce1dc33 100644 --- a/src/state.c +++ b/src/state.c @@ -26,6 +26,7 @@ mrb_open_core(mrb_allocf f, void *ud) static const struct mrb_context mrb_context_zero = { 0 }; mrb_state *mrb; + if (f == NULL) f = mrb_default_allocf; mrb = (mrb_state *)(f)(NULL, NULL, sizeof(mrb_state), ud); if (mrb == NULL) return NULL; -- cgit v1.2.3 From 639f6e2799f33a7889c4ca48ae0e314e67214dfc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 Feb 2019 15:17:56 +0900 Subject: No strict argument check for blocks when keyword arguments exist; ref #4270 --- src/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 49c2bb85c..7904162be 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1810,7 +1810,8 @@ RETRY_TRY_BLOCK: kdict = argv[argc-1]; mrb_hash_check_kdict(mrb, kdict); } - else if (r || argc <= m1+m2+o) { + else if (r || argc <= m1+m2+o + || !(mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc))) { kdict = mrb_hash_new(mrb); kargs = 0; } -- cgit v1.2.3 From ef93ff64054f2aa7e4451387fb768fe2307247a9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 Feb 2019 15:19:20 +0900 Subject: Should not copy keys&values when a hash table is empty; fix #4270 --- src/hash.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 6b92344c3..fd963c3de 100644 --- a/src/hash.c +++ b/src/hash.c @@ -536,6 +536,7 @@ ht_copy(mrb_state *mrb, htable *t) seg = t->rootseg; t2 = ht_new(mrb); + if (t->size == 0) return t2; while (seg) { for (i=0; isize; i++) { -- cgit v1.2.3 From 06ba5905f019ca1a8d8e498fe6dce7a94702c9ad Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 6 Feb 2019 22:01:45 +0900 Subject: Implement inline packed symbols. Small symbols with all alphanumeric characters (<5) are packed in 32bit symbol integer a la base64. This means those small symbols are not listed in `Symbol.all_symbols`. --- include/mruby.h | 3 ++ mrbgems/mruby-symbol-ext/src/symbol.c | 3 +- src/symbol.c | 93 +++++++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 2f2d98677..e9fd08102 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -242,6 +242,9 @@ typedef struct mrb_state { struct symbol_name *symtbl; /* symbol table */ mrb_sym symhash[256]; size_t symcapa; +#ifndef MRB_ENABLE_SYMBOLL_ALL + char symbuf[8]; /* buffer for small symbol names */ +#endif #ifdef MRB_ENABLE_DEBUG_HOOK void (*code_fetch_hook)(struct mrb_state* mrb, struct mrb_irep *irep, mrb_code *pc, mrb_value *regs); diff --git a/mrbgems/mruby-symbol-ext/src/symbol.c b/mrbgems/mruby-symbol-ext/src/symbol.c index 215226502..05e7d5b91 100644 --- a/mrbgems/mruby-symbol-ext/src/symbol.c +++ b/mrbgems/mruby-symbol-ext/src/symbol.c @@ -30,7 +30,8 @@ mrb_sym_all_symbols(mrb_state *mrb, mrb_value self) mrb_value ary = mrb_ary_new_capa(mrb, mrb->symidx); for (i=1, lim=mrb->symidx+1; i 6) return 0; /* too long */ + for (i=0; i 27) lower = 0; + sym |= bits<<(i*6+2); + } + if (lower) { + sym = 0; + for (i=0; i>(i*5+2) & 31; + if (bits == 0) break; + c = pack_table[bits-1]; + buf[i] = c; + } + buf[i] = '\0'; + return buf; + } + + for (i=0; i<5; i++) { + uint32_t bits; + char c; + + bits = sym>>(i*6+2) & 63; + if (bits == 0) break; + c = pack_table[bits-1]; + buf[i] = c; + } + buf[i] = '\0'; + return buf; +} + uint8_t symhash(const char *key, size_t len) { @@ -50,19 +123,23 @@ find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) mrb_sym i; symbol_name *sname; + /* inline symbol */ + i = sym_inline_pack(name, len); + if (i > 0) return i; + i = mrb->symhash[hash]; if (i == 0) return 0; do { sname = &mrb->symtbl[i]; if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return i; + return i<<1; } if (sname->prev == 0xff) { i -= 0xff; sname = &mrb->symtbl[i]; while (mrb->symtbl < sname) { if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return (mrb_sym)(sname - mrb->symtbl); + return (mrb_sym)(sname - mrb->symtbl)<<1; } sname--; } @@ -117,7 +194,7 @@ sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) } mrb->symhash[hash] = sym; - return sym; + return sym<<1; } MRB_API mrb_sym @@ -170,6 +247,13 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { + if (sym & 1) { /* inline packed symbol */ + sym_inline_unpack(sym, mrb->symbuf); + if (lenp) *lenp = strlen(mrb->symbuf); + return mrb->symbuf; + } + + sym >>= 1; if (sym == 0 || mrb->symidx < sym) { if (lenp) *lenp = 0; return NULL; @@ -446,6 +530,9 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ + if (sym&1) { /* inline symbol */ + return mrb_str_new(mrb, name, len); + } return mrb_str_new_static(mrb, name, len); } -- cgit v1.2.3 From 37bc343e0ad6b837de672c8c0cf6bf00876f746b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 6 Feb 2019 23:35:26 +0900 Subject: Disable `Symbol.all_symbols`. --- include/mrbconf.h | 1 + mrbgems/mruby-symbol-ext/src/symbol.c | 9 ++++----- mrbgems/mruby-symbol-ext/test/symbol.rb | 11 +++++++---- src/symbol.c | 6 ++++++ 4 files changed, 18 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/include/mrbconf.h b/include/mrbconf.h index b1aec8334..08e69d3aa 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -120,6 +120,7 @@ /* -DMRB_ENABLE_XXXX to enable following features */ //#define MRB_ENABLE_DEBUG_HOOK /* hooks for debugger */ +//#define MRB_ENABLE_ALL_SYMBOLS /* Symbols.all_symbols */ /* end of configuration */ diff --git a/mrbgems/mruby-symbol-ext/src/symbol.c b/mrbgems/mruby-symbol-ext/src/symbol.c index 05e7d5b91..ccb2971dc 100644 --- a/mrbgems/mruby-symbol-ext/src/symbol.c +++ b/mrbgems/mruby-symbol-ext/src/symbol.c @@ -3,11 +3,6 @@ #include #include -typedef struct symbol_name { - size_t len; - const char *name; -} symbol_name; - /* * call-seq: * Symbol.all_symbols => array @@ -23,6 +18,7 @@ typedef struct symbol_name { * :Tms, :getwd, :$=, :ThreadGroup, * :wait2, :$>] */ +#ifdef MRB_ENABLE_ALL_SYMBOLS static mrb_value mrb_sym_all_symbols(mrb_state *mrb, mrb_value self) { @@ -36,6 +32,7 @@ mrb_sym_all_symbols(mrb_state *mrb, mrb_value self) return ary; } +#endif /* * call-seq: @@ -61,7 +58,9 @@ void mrb_mruby_symbol_ext_gem_init(mrb_state* mrb) { struct RClass *s = mrb->symbol_class; +#ifdef MRB_ENABLE_ALL_SYMBOLS mrb_define_class_method(mrb, s, "all_symbols", mrb_sym_all_symbols, MRB_ARGS_NONE()); +#endif mrb_define_method(mrb, s, "length", mrb_sym_length, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "size", mrb_sym_length, MRB_ARGS_NONE()); } diff --git a/mrbgems/mruby-symbol-ext/test/symbol.rb b/mrbgems/mruby-symbol-ext/test/symbol.rb index 2c7a62b0c..61ecad247 100644 --- a/mrbgems/mruby-symbol-ext/test/symbol.rb +++ b/mrbgems/mruby-symbol-ext/test/symbol.rb @@ -1,10 +1,13 @@ +# coding: utf-8 ## # Symbol(Ext) Test -assert('Symbol.all_symbols') do - foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort - symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort - assert_equal foo, symbols +if Symbol.respond_to?(:all_symbols) + assert('Symbol.all_symbols') do + foo = [:__symbol_test_1, :__symbol_test_2, :__symbol_test_3].sort + symbols = Symbol.all_symbols.select{|sym|sym.to_s.include? '__symbol_test'}.sort + assert_equal foo, symbols + end end %w[size length].each do |n| diff --git a/src/symbol.c b/src/symbol.c index ab7504772..9cc566245 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -28,6 +28,7 @@ sym_validate_len(mrb_state *mrb, size_t len) } } +#ifndef MRB_ENABLE_ALL_SYMBOLS static char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static mrb_sym @@ -100,6 +101,7 @@ sym_inline_unpack(mrb_sym sym, char *buf) buf[i] = '\0'; return buf; } +#endif uint8_t symhash(const char *key, size_t len) @@ -123,9 +125,11 @@ find_symbol(mrb_state *mrb, const char *name, uint16_t len, uint8_t hash) mrb_sym i; symbol_name *sname; +#ifndef MRB_ENABLE_ALL_SYMBOLS /* inline symbol */ i = sym_inline_pack(name, len); if (i > 0) return i; +#endif i = mrb->symhash[hash]; if (i == 0) return 0; @@ -247,11 +251,13 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { +#ifndef MRB_ENABLE_ALL_SYMBOLS if (sym & 1) { /* inline packed symbol */ sym_inline_unpack(sym, mrb->symbuf); if (lenp) *lenp = strlen(mrb->symbuf); return mrb->symbuf; } +#endif sym >>= 1; if (sym == 0 || mrb->symidx < sym) { -- cgit v1.2.3 From bedd67257190d0f290d37938cfbd9e7936dd6f73 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 14 Feb 2019 18:44:00 +0900 Subject: Add `const` to `pack_table` to `src/symbol.c` --- src/symbol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 9cc566245..c3f06be66 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -29,13 +29,13 @@ sym_validate_len(mrb_state *mrb, size_t len) } #ifndef MRB_ENABLE_ALL_SYMBOLS -static char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static mrb_sym sym_inline_pack(const char *name, uint16_t len) { char c; - char *p; + const char *p; int i; mrb_sym sym = 0; int lower = 1; -- cgit v1.2.3 From 921af6923d5e55992983d2f4e7930b8a97571448 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 14 Feb 2019 18:48:41 +0900 Subject: Use `mrb_assert()` for checking `sym` in `sym_inline_unpack()` --- src/symbol.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 9cc566245..ac313665c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -73,9 +73,9 @@ sym_inline_unpack(mrb_sym sym, char *buf) { int i; - if (sym == 0) return NULL; - if ((sym&1) == 0) return NULL; /* need to be inline sym */ - if (sym&2) { /* all lower case (5bits/char) */ + mrb_assert(sym&1); + + if (sym&2) { /* all lower case (5bits/char) */ for (i=0; i<6; i++) { uint32_t bits; char c; -- cgit v1.2.3 From 5b10439f6fcf49a5283e4e01b920f350db36e684 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 15 Feb 2019 19:48:00 +0900 Subject: Extract code fragment for unpacking into method in `sym_inline_unpack()` --- src/symbol.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 19e5c2d62..620ae3418 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -69,31 +69,15 @@ sym_inline_pack(const char *name, uint16_t len) } static const char* -sym_inline_unpack(mrb_sym sym, char *buf) +sym_inline_unpack_with_bit(mrb_sym sym, char *buf, int bit_per_char) { int i; - mrb_assert(sym&1); - - if (sym&2) { /* all lower case (5bits/char) */ - for (i=0; i<6; i++) { - uint32_t bits; - char c; - - bits = sym>>(i*5+2) & 31; - if (bits == 0) break; - c = pack_table[bits-1]; - buf[i] = c; - } - buf[i] = '\0'; - return buf; - } - - for (i=0; i<5; i++) { + for (i=0; i<30/bit_per_char; i++) { uint32_t bits; char c; - bits = sym>>(i*6+2) & 63; + bits = sym>>(i*bit_per_char+2) & (1< Date: Sat, 16 Feb 2019 20:48:33 +0900 Subject: Add length argument for `sym_inline_unpack()` `sym_inline_unpack_with_bit()` is moved inside of `sym_inline_unpack()` because this is used only one place. --- src/symbol.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 620ae3418..e09e9019d 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -69,33 +69,22 @@ sym_inline_pack(const char *name, uint16_t len) } static const char* -sym_inline_unpack_with_bit(mrb_sym sym, char *buf, int bit_per_char) +sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) { + int bit_per_char = sym&2 ? 5 : 6; /* all lower case if `sym&2` is true */ int i; - for (i=0; i<30/bit_per_char; i++) { - uint32_t bits; - char c; + mrb_assert(sym&1); - bits = sym>>(i*bit_per_char+2) & (1<>(i*bit_per_char+2) & (1<symbuf); - if (lenp) *lenp = strlen(mrb->symbuf); - return mrb->symbuf; + return sym_inline_unpack(sym, mrb->symbuf, lenp); } #endif -- cgit v1.2.3 From 81cbc92513b82bf4ee173fab0a7779ac05a8ef04 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 16 Feb 2019 21:26:45 +0900 Subject: Fix inline packed symbols on 32 bit mode with MRB_WORD_BOXING --- src/symbol.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 620ae3418..1bc9f2676 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -34,13 +34,18 @@ static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS static mrb_sym sym_inline_pack(const char *name, uint16_t len) { + enum { + lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5, + mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6 + }; + char c; const char *p; int i; mrb_sym sym = 0; int lower = 1; - if (len > 6) return 0; /* too long */ + if (len > lower_length_max) return 0; /* too long */ for (i=0; i mix_length_max) return 0; return sym | 1; } -- cgit v1.2.3 From 5067a5cd584c4457934872d50cfb33735d55241d Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 16 Feb 2019 22:13:16 +0900 Subject: Use `const int` instead of `enum` --- src/symbol.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 1bc9f2676..80437e39e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -34,10 +34,8 @@ static const char pack_table[] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS static mrb_sym sym_inline_pack(const char *name, uint16_t len) { - enum { - lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5, - mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6 - }; + const int lower_length_max = (MRB_SYMBOL_BITSIZE - 2) / 5; + const int mix_length_max = (MRB_SYMBOL_BITSIZE - 2) / 6; char c; const char *p; -- cgit v1.2.3 From 15344dfd0b605f391ea2c1f171eb8595c9831df1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 18 Feb 2019 16:12:12 +0900 Subject: Remove unneeded `memset()` in `src/backtrace.c` --- src/backtrace.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/backtrace.c b/src/backtrace.c index 57ae7fd7f..c9da2026e 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -206,7 +206,6 @@ packed_backtrace(mrb_state *mrb) each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len); size = len * sizeof(struct backtrace_location); ptr = mrb_malloc(mrb, size); - if (ptr) memset(ptr, 0, size); backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type); backtrace->flags = (unsigned int)len; each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr); -- cgit v1.2.3 From a28d7143986de8bcb1dbfa3a202079b3a25bf6f2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 18 Feb 2019 16:38:56 +0900 Subject: Reorder members in `struct backtrace_location` `sizeof(struct backtrace_location)` is 24 bytes -> 16 bytes in LP64 data model etc. --- src/backtrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/backtrace.c b/src/backtrace.c index 57ae7fd7f..ef5f0dc38 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -17,8 +17,8 @@ struct backtrace_location { int lineno; - const char *filename; mrb_sym method_id; + const char *filename; }; typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*); -- cgit v1.2.3 From 9215c854502da336efe8ece755450478f320349f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 18 Feb 2019 17:21:08 +0900 Subject: Parenthesize expression to suppress warning; ref #4278 --- src/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 8424cecd9..87c4ca11e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -80,7 +80,7 @@ sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) mrb_assert(sym&1); for (i=0; i<30/bit_per_char; i++) { - uint32_t bits = sym>>(i*bit_per_char+2) & (1<>(i*bit_per_char+2) & ((1< Date: Mon, 25 Feb 2019 20:39:20 +0900 Subject: Refactor `src/backtrace.c` - Move calling `mrb_debug_get_filename()` to after `lineno` check. - Remove unneeded array check in `print_backtrace()`. - Add a few `const` qualifier. --- src/backtrace.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/backtrace.c b/src/backtrace.c index 8f28c71cb..521cd6c1b 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -21,7 +21,7 @@ struct backtrace_location { const char *filename; }; -typedef void (*each_backtrace_func)(mrb_state*, struct backtrace_location*, void*); +typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*, void*); static const mrb_data_type bt_type = { "Backtrace", mrb_free }; @@ -57,11 +57,11 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu else { pc = pc0; } - loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); - loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); + loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); if (loc.lineno == -1) continue; + loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); if (!loc.filename) { loc.filename = "(unknown)"; } @@ -80,8 +80,6 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) mrb_int n; FILE *stream = stderr; - if (!mrb_array_p(backtrace)) return; - n = RARRAY_LEN(backtrace) - 1; if (n == 0) return; @@ -96,7 +94,7 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) } static int -packed_bt_len(struct backtrace_location *bt, int n) +packed_bt_len(const struct backtrace_location *bt, int n) { int len = 0; int i; @@ -113,7 +111,7 @@ static void print_packed_backtrace(mrb_state *mrb, mrb_value packed) { FILE *stream = stderr; - struct backtrace_location *bt; + const struct backtrace_location *bt; int n, i; int ai = mrb_gc_arena_save(mrb); @@ -124,7 +122,7 @@ print_packed_backtrace(mrb_state *mrb, mrb_value packed) if (packed_bt_len(bt, n) == 0) return; fprintf(stream, "trace (most recent call last):\n"); for (i = 0; ifilename == NULL) continue; fprintf(stream, "\t[%d] %s:%d", i, entry->filename, entry->lineno); if (entry->method_id != 0) { @@ -172,7 +170,7 @@ mrb_print_backtrace(mrb_state *mrb) static void count_backtrace_i(mrb_state *mrb, - struct backtrace_location *loc, + const struct backtrace_location *loc, void *data) { int *lenp = (int*)data; @@ -183,7 +181,7 @@ count_backtrace_i(mrb_state *mrb, static void pack_backtrace_i(mrb_state *mrb, - struct backtrace_location *loc, + const struct backtrace_location *loc, void *data) { struct backtrace_location **pptr = (struct backtrace_location**)data; @@ -229,7 +227,7 @@ mrb_keep_backtrace(mrb_state *mrb, mrb_value exc) mrb_value mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) { - struct backtrace_location *bt; + const struct backtrace_location *bt; mrb_int n, i; int ai; @@ -244,7 +242,7 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace) backtrace = mrb_ary_new_capa(mrb, n); ai = mrb_gc_arena_save(mrb); for (i = 0; i < n; i++) { - struct backtrace_location *entry = &bt[i]; + const struct backtrace_location *entry = &bt[i]; mrb_value btline; if (entry->filename == NULL) continue; -- cgit v1.2.3 From 62bb9c643629883c8e1b6ea37791f4c64468f4c2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 27 Feb 2019 20:58:20 +0900 Subject: Add newline to warning by `mrb_warn()` --- src/error.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/error.c b/src/error.c index 57cdfcfe1..50d1ab6f9 100644 --- a/src/error.c +++ b/src/error.c @@ -376,6 +376,7 @@ mrb_warn(mrb_state *mrb, const char *fmt, ...) str = mrb_vformat(mrb, fmt, ap); fputs("warning: ", stderr); fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr); + putc('\n', stderr); va_end(ap); #endif } -- cgit v1.2.3 From 13e0a48e3cac92d9d6063769ab6ac60ada8d393e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 13:50:56 +0900 Subject: Print length of the `iseq` in code dump header; fix #4304 --- src/codedump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/codedump.c b/src/codedump.c index 4d56fd427..c9c3b25ef 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -74,8 +74,8 @@ codedump(mrb_state *mrb, mrb_irep *irep) const char *file = NULL, *next_file; if (!irep) return; - printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, - irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); + printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep, + irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen); if (irep->lv) { int i; -- cgit v1.2.3 From 73091ab20288d196e774cefd234660e5c6fefc14 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 2 Mar 2019 15:45:15 +0900 Subject: Do not apply `mrb_ptr()` to immediate objects; fix #4307 --- src/object.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/object.c b/src/object.c index b764fc8ef..d45ab27c7 100644 --- a/src/object.c +++ b/src/object.c @@ -434,8 +434,10 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj) mrb_str_cat_lit(mrb, str, "#<"); mrb_str_cat_cstr(mrb, str, cname); - mrb_str_cat_lit(mrb, str, ":"); - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + if (!mrb_immediate_p(obj)) { + mrb_str_cat_lit(mrb, str, ":"); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); + } mrb_str_cat_lit(mrb, str, ">"); return str; -- cgit v1.2.3 From 376dd992f1a61002a567ef371dd3cdd070bc8376 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 3 Mar 2019 20:45:44 +0900 Subject: Extract similar code fragment to method in `src/class.c` --- src/class.c | 56 +++++++++++++++++--------------------------------------- 1 file changed, 17 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 359bb4fea..bb9515bbd 100644 --- a/src/class.c +++ b/src/class.c @@ -122,6 +122,19 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o)); } +static mrb_value +class_name_str(mrb_state *mrb, struct RClass* c) +{ + mrb_value path = mrb_class_path(mrb, c); + if (mrb_nil_p(path)) { + path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#"); + } + return path; +} + static struct RClass* class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id) { @@ -1696,14 +1709,8 @@ mrb_class_real(struct RClass* cl) MRB_API const char* mrb_class_name(mrb_state *mrb, struct RClass* c) { - mrb_value path = mrb_class_path(mrb, c); - if (mrb_nil_p(path)) { - path = c->tt == MRB_TT_MODULE ? mrb_str_new_lit(mrb, "#"); - } - return RSTRING_PTR(path); + mrb_value name = class_name_str(mrb, c); + return RSTRING_PTR(name); } MRB_API const char* @@ -1818,12 +1825,10 @@ mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { - mrb_value str; if (mrb_type(klass) == MRB_TT_SCLASS) { mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__")); - - str = mrb_str_new_lit(mrb, "#"); } else { - struct RClass *c; - mrb_value path; - - str = mrb_str_new_capa(mrb, 32); - c = mrb_class_ptr(klass); - path = mrb_class_path(mrb, c); - - if (mrb_nil_p(path)) { - switch (mrb_type(klass)) { - case MRB_TT_CLASS: - mrb_str_cat_lit(mrb, str, "#"); - } - else { - return path; - } + return class_name_str(mrb, mrb_class_ptr(klass)); } } -- cgit v1.2.3 From 425e6e0ffb0e2935b800866443fb18ccb26a97e4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 11 Mar 2019 17:26:19 +0900 Subject: Reduce `String` creation in `check_(cv|const)_name_sym` --- mrbgems/mruby-metaprog/src/metaprog.c | 17 ++++++++--------- src/class.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 25c153cee..75913dab5 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -400,21 +400,20 @@ mod_define_singleton_method(mrb_state *mrb, mrb_value self) return mrb_symbol_value(mid); } -static void -check_cv_name_str(mrb_state *mrb, mrb_value str) +static mrb_bool +cv_name_p(mrb_state *mrb, const char *name, mrb_int len) { - const char *s = RSTRING_PTR(str); - mrb_int len = RSTRING_LEN(str); - - if (len < 3 || !(s[0] == '@' && s[1] == '@')) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); - } + return len > 2 && name[0] == '@' && name[1] == '@'; } static void check_cv_name_sym(mrb_state *mrb, mrb_sym id) { - check_cv_name_str(mrb, mrb_sym2str(mrb, id)); + mrb_int len; + const char *name = mrb_sym2name_len(mrb, id, &len); + if (!cv_name_p(mrb, name, len)) { + mrb_name_error(mrb, id, "'%S' is not allowed as a class variable name", mrb_sym2str(mrb, id)); + } } /* 15.2.2.4.39 */ diff --git a/src/class.c b/src/class.c index bb9515bbd..9d6fd631f 100644 --- a/src/class.c +++ b/src/class.c @@ -1895,18 +1895,20 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static void -check_const_name_str(mrb_state *mrb, mrb_value str) +static mrb_bool +const_name_p(mrb_state *mrb, const char *name, mrb_int len) { - if (RSTRING_LEN(str) < 1 || !ISUPPER(*RSTRING_PTR(str))) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "wrong constant name %S", str); - } + return len > 0 && ISUPPER(name[0]); } static void check_const_name_sym(mrb_state *mrb, mrb_sym id) { - check_const_name_str(mrb, mrb_sym2str(mrb, id)); + mrb_int len; + const char *name = mrb_sym2name_len(mrb, id, &len); + if (!const_name_p(mrb, name, len)) { + mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); + } } static mrb_value -- cgit v1.2.3 From 16b1b2978e4f4d838f3d12e7221139a92429603b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 14 Mar 2019 23:09:05 +0900 Subject: Fix constant name validation `X!` etc are invalid constant name. --- include/mruby/variable.h | 1 + src/class.c | 2 +- src/variable.c | 20 +++++++++++++------- test/t/module.rb | 24 ++++++++++-------------- 4 files changed, 25 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/include/mruby/variable.h b/include/mruby/variable.h index 68a2a7121..ba6037959 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -123,6 +123,7 @@ mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value); mrb_value mrb_mod_class_variables(mrb_state*, mrb_value); mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym); mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym); +mrb_bool mrb_ident_p(const char *s, mrb_int len); /* GC functions */ void mrb_gc_mark_gv(mrb_state*); diff --git a/src/class.c b/src/class.c index 9d6fd631f..da95f5c22 100644 --- a/src/class.c +++ b/src/class.c @@ -1898,7 +1898,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) static mrb_bool const_name_p(mrb_state *mrb, const char *name, mrb_int len) { - return len > 0 && ISUPPER(name[0]); + return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); } static void diff --git a/src/variable.c b/src/variable.c index 14e9da9ef..b712af261 100644 --- a/src/variable.c +++ b/src/variable.c @@ -428,22 +428,17 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym); } -#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) - MRB_API mrb_bool mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) { const char *s; - mrb_int i, len; + mrb_int len; s = mrb_sym2name_len(mrb, iv_name, &len); if (len < 2) return FALSE; if (s[0] != '@') return FALSE; if (s[1] == '@') return FALSE; - for (i=1; i Date: Fri, 15 Mar 2019 13:17:40 +0900 Subject: Use `fmt_fp()` for portable float representation. --- src/fmt_fp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 7028d3aac..14c74ef9e 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -1,5 +1,5 @@ #ifndef MRB_WITHOUT_FLOAT -#ifdef MRB_DISABLE_STDIO +#if defined(MRB_DISABLE_STDIO) || defined(_WIN32) || defined(_WIN64) /* Most code in this file originates from musl (src/stdio/vfprintf.c) -- cgit v1.2.3 From b588e5a5b7cfc0e7a1c84c235a0f5daa5bf83a47 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 17 Mar 2019 16:58:31 +0900 Subject: Fix class/instance variable name validation - `@@?` etc are invalid class variable name. - `@1` etc are invalid instance variable name. --- mrbgems/mruby-metaprog/src/metaprog.c | 3 ++- mrbgems/mruby-metaprog/test/metaprog.rb | 38 +++++++++++++++++++++++++++++++++ src/variable.c | 2 +- test/t/kernel.rb | 7 +++--- 4 files changed, 44 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 75913dab5..0aafb4c34 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -403,7 +403,8 @@ mod_define_singleton_method(mrb_state *mrb, mrb_value self) static mrb_bool cv_name_p(mrb_state *mrb, const char *name, mrb_int len) { - return len > 2 && name[0] == '@' && name[1] == '@'; + return len > 2 && name[0] == '@' && name[1] == '@' && + !ISDIGIT(name[2]) && mrb_ident_p(name+2, len-2); } static void diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 8bc3719b8..1262c9945 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -34,6 +34,30 @@ assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do assert_false o.instance_variable_defined?("@b") assert_true o.instance_variable_defined?("@a"[0,2]) assert_true o.instance_variable_defined?("@abc"[0,2]) + assert_raise(NameError) { o.instance_variable_defined?("@0") } +end + +assert('Kernel#instance_variable_get', '15.3.1.3.21') do + o = Class.new { attr_accessor :foo, :bar }.new + o.foo = "one" + o.bar = 2 + assert_equal("one", o.instance_variable_get(:@foo)) + assert_equal(2, o.instance_variable_get("@bar")) + assert_equal(nil, o.instance_variable_get(:@baz)) + %w[foo @1].each do |n| + assert_raise(NameError) { o.instance_variable_get(n) } + end +end + +assert('Kernel#instance_variable_set', '15.3.1.3.22') do + o = Class.new { attr_reader :foo, :_bar }.new + assert_equal("one", o.instance_variable_set(:@foo, "one")) + assert_equal("one", o.foo) + assert_equal(2, o.instance_variable_set("@_bar", 2)) + assert_equal(2, o._bar) + %w[@6 @% @@a @ a].each do |n| + assert_raise(NameError) { o.instance_variable_set(n, 1) } + end end assert('Kernel#instance_variables', '15.3.1.3.23') do @@ -125,6 +149,7 @@ assert('Module#class_variable_defined?', '15.2.2.4.16') do assert_true Test4ClassVariableDefined.class_variable_defined?(:@@cv) assert_false Test4ClassVariableDefined.class_variable_defined?(:@@noexisting) + assert_raise(NameError) { Test4ClassVariableDefined.class_variable_defined?("@@2") } end assert('Module#class_variable_get', '15.2.2.4.17') do @@ -133,6 +158,10 @@ assert('Module#class_variable_get', '15.2.2.4.17') do end assert_equal 99, Test4ClassVariableGet.class_variable_get(:@@cv) + assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(:@@a) } + %w[@@a? @@! @a a].each do |n| + assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(n) } + end end assert('Module#class_variable_set', '15.2.2.4.18') do @@ -148,6 +177,9 @@ assert('Module#class_variable_set', '15.2.2.4.18') do assert_true Test4ClassVariableSet.class_variables.include? :@@cv assert_equal 99, Test4ClassVariableSet.class_variable_get(:@@cv) assert_equal 101, Test4ClassVariableSet.new.foo + %w[@@ @@1 @@x= @x @ x 1].each do |n| + assert_raise(NameError) { Test4ClassVariableSet.class_variable_set(n, 1) } + end end assert('Module#class_variables', '15.2.2.4.19') do @@ -223,6 +255,12 @@ assert('Module#remove_class_variable', '15.2.2.4.39') do assert_equal 99, Test4RemoveClassVariable.remove_class_variable(:@@cv) assert_false Test4RemoveClassVariable.class_variables.include? :@@cv + assert_raise(NameError) do + Test4RemoveClassVariable.remove_class_variable(:@@cv) + end + assert_raise(NameError) do + Test4RemoveClassVariable.remove_class_variable(:@v) + end end assert('Module#remove_method', '15.2.2.4.41') do diff --git a/src/variable.c b/src/variable.c index b712af261..90efe9e0e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -437,7 +437,7 @@ mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) s = mrb_sym2name_len(mrb, iv_name, &len); if (len < 2) return FALSE; if (s[0] != '@') return FALSE; - if (s[1] == '@') return FALSE; + if (ISDIGIT(s[1])) return FALSE; return mrb_ident_p(s+1, len-1); } diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 74176fbd0..d99358c0c 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -391,11 +391,10 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do tri = Test4RemoveInstanceVar.new assert_equal 99, tri.var - tri.remove + assert_equal 99, tri.remove assert_equal nil, tri.var - assert_raise NameError do - tri.remove - end + assert_raise(NameError) { tri.remove } + assert_raise(NameError) { tri.remove_instance_variable(:var) } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' -- cgit v1.2.3 From a41b02ab918d7fb976234e1b07e2e60eff4d9f96 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 21 Mar 2019 21:36:54 +0900 Subject: Fix `Float#eql?` --- src/numeric.c | 2 +- test/t/float.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index fa9daf8a7..4128ea3a6 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -369,7 +369,7 @@ flo_eql(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); if (!mrb_float_p(y)) return mrb_false_value(); - return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y)); + return mrb_bool_value(mrb_float(x) == mrb_float(y)); } /* 15.2.9.3.7 */ diff --git a/test/t/float.rb b/test/t/float.rb index c137698d3..910d7b1d5 100644 --- a/test/t/float.rb +++ b/test/t/float.rb @@ -239,4 +239,10 @@ assert('Float#to_s') do end end +assert('Float#eql?') do + assert_true(5.0.eql?(5.0)) + assert_false(5.0.eql?(5)) + assert_false(5.0.eql?("5.0")) +end + end # const_defined?(:Float) -- cgit v1.2.3 From 10a8e0f1058ef5a1f8af132616e92163c7159cd3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 24 Mar 2019 20:55:04 +0900 Subject: Fix arguments spec in `src/proc.c` --- src/proc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/proc.c b/src/proc.c index dcbeb4f62..dab95e465 100644 --- a/src/proc.c +++ b/src/proc.c @@ -301,7 +301,7 @@ mrb_init_proc(mrb_state *mrb) call_irep->ilen = 1; call_irep->nregs = 2; /* receiver and block */ - mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY()); + mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); @@ -310,6 +310,6 @@ mrb_init_proc(mrb_state *mrb) mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "call"), m); mrb_define_method_raw(mrb, mrb->proc_class, mrb_intern_lit(mrb, "[]"), m); - mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.2.6 */ - mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()); /* 15.3.1.3.27 */ + mrb_define_class_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.2.6 */ + mrb_define_method(mrb, mrb->kernel_module, "lambda", proc_lambda, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); /* 15.3.1.3.27 */ } -- cgit v1.2.3 From 33a9840e4a2db7b5136850f23b0185a7d0a6c9c9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 25 Mar 2019 20:28:21 +0900 Subject: Need to check length before packing a symbol; fix #4340 --- src/symbol.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 87c4ca11e..561c5e2fb 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -53,6 +53,7 @@ sym_inline_pack(const char *name, uint16_t len) if (p == 0) return 0; /* non alnum char */ bits = (uint32_t)(p - pack_table)+1; if (bits > 27) lower = 0; + if (i >= mix_length_max) break; sym |= bits<<(i*6+2); } if (lower) { -- cgit v1.2.3 From b489ddcbd16535b1a4bd89d4890135fe2c734baa Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 25 Mar 2019 21:39:11 +0900 Subject: Remove implementation of `Symbol#===` For reducing program size. --- src/symbol.c | 21 --------------------- test/t/symbol.rb | 4 ++-- 2 files changed, 2 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 561c5e2fb..9500e6e36 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -306,26 +306,6 @@ mrb_init_symtbl(mrb_state *mrb) * */ - -/* 15.2.11.3.1 */ -/* - * call-seq: - * sym == obj -> true or false - * - * Equality---If sym and obj are exactly the same - * symbol, returns true. - */ - -static mrb_value -sym_equal(mrb_state *mrb, mrb_value sym1) -{ - mrb_value sym2; - - mrb_get_args(mrb, "o", &sym2); - - return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2)); -} - /* 15.2.11.3.2 */ /* 15.2.11.3.3 */ /* @@ -585,7 +565,6 @@ mrb_init_symbol(mrb_state *mrb) MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); mrb_undef_class_method(mrb, sym, "new"); - mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */ mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ diff --git a/test/t/symbol.rb b/test/t/symbol.rb index fdce0f378..5c674a9cb 100644 --- a/test/t/symbol.rb +++ b/test/t/symbol.rb @@ -13,8 +13,8 @@ assert('Symbol', '15.2.11') do end assert('Symbol#===', '15.2.11.3.1') do - assert_true :abc == :abc - assert_false :abc == :cba + assert_true :abc === :abc + assert_false :abc === :cba end assert('Symbol#id2name', '15.2.11.3.2') do -- cgit v1.2.3 From a5a6b51126875e578ef1834c8af06141934df7dd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 25 Mar 2019 21:06:54 +0900 Subject: Use uppercase version of `ctype` macros e.g. `ISSPACE`; fix #4338 --- mrbgems/mruby-bin-mirb/tools/mirb/mirb.c | 22 +++++++++++----------- mrbgems/mruby-compiler/core/parse.y | 12 ++++++------ mrbgems/mruby-pack/src/pack.c | 6 +++--- src/string.c | 6 +++--- 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c index 9519d88bb..17b2ca16c 100644 --- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c @@ -6,6 +6,15 @@ ** immediately. It's a REPL... */ +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -49,15 +58,6 @@ #define SIGJMP_BUF jmp_buf #endif -#include -#include -#include -#include -#include -#include -#include -#include - #ifdef ENABLE_READLINE static const char history_file_name[] = ".mirb_history"; @@ -373,7 +373,7 @@ check_keyword(const char *buf, const char *word) size_t len = strlen(word); /* skip preceding spaces */ - while (*p && isspace((unsigned char)*p)) { + while (*p && ISSPACE(*p)) { p++; } /* check keyword */ @@ -383,7 +383,7 @@ check_keyword(const char *buf, const char *word) p += len; /* skip trailing spaces */ while (*p) { - if (!isspace((unsigned char)*p)) return 0; + if (!ISSPACE(*p)) return 0; p++; } return 1; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 0aabc2f34..90f01e3a8 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4888,10 +4888,10 @@ parser_yylex(parser_state *p) } newtok(p); /* need support UTF-8 if configured */ - if ((isalnum(c) || c == '_')) { + if ((ISALNUM(c) || c == '_')) { int c2 = nextc(p); pushback(p, c2); - if ((isalnum(c2) || c2 == '_')) { + if ((ISALNUM(c2) || c2 == '_')) { goto ternary; } } @@ -5459,7 +5459,7 @@ parser_yylex(parser_state *p) } else { term = nextc(p); - if (isalnum(term)) { + if (ISALNUM(term)) { yyerror(p, "unknown type of %string"); return 0; } @@ -5603,7 +5603,7 @@ parser_yylex(parser_state *p) do { tokadd(p, c); c = nextc(p); - } while (c >= 0 && isdigit(c)); + } while (c >= 0 && ISDIGIT(c)); pushback(p, c); if (last_state == EXPR_FNAME) goto gvar; tokfix(p); @@ -5645,7 +5645,7 @@ parser_yylex(parser_state *p) } return 0; } - else if (isdigit(c)) { + else if (ISDIGIT(c)) { if (p->tidx == 1) { yyerror_i(p, "'@%c' is not allowed as an instance variable name", c); } @@ -5802,7 +5802,7 @@ parser_yylex(parser_state *p) mrb_sym ident = intern_cstr(tok(p)); pylval.id = ident; - if (last_state != EXPR_DOT && islower(tok(p)[0]) && local_var_p(p, ident)) { + if (last_state != EXPR_DOT && ISLOWER(tok(p)[0]) && local_var_p(p, ident)) { p->lstate = EXPR_END; } } diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 2e68f35ed..ac29fdbf3 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -627,7 +627,7 @@ unpack_a(mrb_state *mrb, const void *src, int slen, mrb_value ary, long count, u } } else if (!(flags & PACK_FLAG_a)) { /* "A" */ - while (copylen > 0 && (sptr[copylen - 1] == '\0' || isspace(sptr[copylen - 1]))) { + while (copylen > 0 && (sptr[copylen - 1] == '\0' || ISSPACE(sptr[copylen - 1]))) { copylen--; } } @@ -1072,9 +1072,9 @@ alias: /* read suffix [0-9*_!<>] */ while (tmpl->idx < tlen) { ch = tptr[tmpl->idx++]; - if (isdigit(ch)) { + if (ISDIGIT(ch)) { count = ch - '0'; - while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) { + while (tmpl->idx < tlen && ISDIGIT(tptr[tmpl->idx])) { count = count * 10 + (tptr[tmpl->idx++] - '0'); if (count < 0) { mrb_raise(mrb, E_RUNTIME_ERROR, "too big template length"); diff --git a/src/string.c b/src/string.c index 19962fb30..8efea84ab 100644 --- a/src/string.c +++ b/src/string.c @@ -2844,7 +2844,7 @@ mrb_float_read(const char *string, char **endPtr) */ p = string; - while (isspace(*p)) { + while (ISSPACE(*p)) { p += 1; } if (*p == '-') { @@ -2867,7 +2867,7 @@ mrb_float_read(const char *string, char **endPtr) for (mantSize = 0; ; mantSize += 1) { c = *p; - if (!isdigit(c)) { + if (!ISDIGIT(c)) { if ((c != '.') || (decPt >= 0)) { break; } @@ -2952,7 +2952,7 @@ mrb_float_read(const char *string, char **endPtr) } expSign = FALSE; } - while (isdigit(*p)) { + while (ISDIGIT(*p)) { exp = exp * 10 + (*p - '0'); if (exp > 19999) { exp = 19999; -- cgit v1.2.3 From c2660b8111cd6cd98a41aa257c503cbd3a7cf881 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 26 Mar 2019 10:23:52 +0900 Subject: Fix missing `MRB_API` prefix for functions below; clse #4267 Functions to add prototypes to headers: * mrb_ary_splice() * mrb_notimplement() * mrb_vformat() * mrb_cstr_to_dbl() * mrb_cstr_to_inum() Functions to be made `static` (`MRB_API` was not needed): * mrb_mod_module_function() * mrb_obj_hash() * mrb_str_len_to_inum() Functions to remove `MRB_API` from definitions (referenced from within `libmruby`): * mrb_mod_cv_defined() * mrb_mod_cv_get() * mrb_f_send() --- include/mruby.h | 5 +++++ include/mruby/array.h | 16 ++++++++++++++++ include/mruby/error.h | 2 +- include/mruby/string.h | 2 ++ src/class.c | 2 +- src/kernel.c | 2 +- src/string.c | 4 ++-- src/variable.c | 4 ++-- src/vm.c | 2 +- 9 files changed, 31 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 9792d7482..f2c800eec 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -708,6 +708,9 @@ MRB_API struct RClass * mrb_module_get(mrb_state *mrb, const char *name); * @return [struct RClass *] A reference to the module. */ MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name); +/* a function to raise NotImplementedError with current method name */ +MRB_API void mrb_notimplement(mrb_state*); +/* a function to be replacement of unimplemented method */ MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value); /** @@ -1143,6 +1146,8 @@ MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...); MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...); MRB_API void mrb_print_backtrace(mrb_state *mrb); MRB_API void mrb_print_error(mrb_state *mrb); +/* function for `raisef` formatting */ +MRB_API mrb_value mrb_vformat(mrb_state *mrb, const char *format, va_list ap); /* macros to get typical exception objects note: diff --git a/include/mruby/array.h b/include/mruby/array.h index 2457f68f2..2e6951c0d 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -227,6 +227,22 @@ MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item */ MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset); +/* + * Replace subsequence of an array. + * + * Equivalent to: + * + * ary.shift + * + * @param mrb The mruby state reference. + * @param self The array from which the value will be shifted. + * @param head Beginning position of a replacement subsequence. + * @param len Length of a replacement subsequence. + * @param rpl The array of replacement elements. + * @return The receiver array. + */ +MRB_API mrb_value mrb_ary_splice(mrb_state *mrb, mrb_value self, mrb_int head, mrb_int len, mrb_value rpl); + /* * Shifts the first element from the array. * diff --git a/include/mruby/error.h b/include/mruby/error.h index 1587795fc..237c701ad 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -29,7 +29,7 @@ MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc); MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb); MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...); -/* declaration for fail method */ +/* declaration for `fail` method */ MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value); struct RBreak { diff --git a/include/mruby/string.h b/include/mruby/string.h index 6fe0556b0..0b90debec 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -352,7 +352,9 @@ MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); MRB_API mrb_value mrb_str_to_inum(mrb_state *mrb, mrb_value str, mrb_int base, mrb_bool badcheck); +MRB_API mrb_value mrb_cstr_to_inum(mrb_state *mrb, const char *s, mrb_int base, mrb_bool badcheck); MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck); +MRB_API double mrb_cstr_to_dbl(mrb_state *mrb, const char *s, mrb_bool badcheck); /* * Returns a converted string type. diff --git a/src/class.c b/src/class.c index da95f5c22..3354617bb 100644 --- a/src/class.c +++ b/src/class.c @@ -2106,7 +2106,7 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) return mrb_bool_value(eqq); } -MRB_API mrb_value +static mrb_value mrb_mod_module_function(mrb_state *mrb, mrb_value mod) { mrb_value *argv; diff --git a/src/kernel.c b/src/kernel.c index 8845cbce6..7890e3dac 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -492,7 +492,7 @@ mrb_obj_frozen(mrb_state *mrb, mrb_value self) * Hash. Any hash value that exceeds the capacity of a * Fixnum will be truncated before being used. */ -MRB_API mrb_value +static mrb_value mrb_obj_hash(mrb_state *mrb, mrb_value self) { return mrb_fixnum_value(mrb_obj_id(self)); diff --git a/src/string.c b/src/string.c index 8efea84ab..63c592d59 100644 --- a/src/string.c +++ b/src/string.c @@ -2006,7 +2006,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) return result; } -MRB_API mrb_value +static mrb_value mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, int badcheck) { const char *p = str; @@ -2174,7 +2174,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, } MRB_API mrb_value -mrb_cstr_to_inum(mrb_state *mrb, const char *str, int base, int badcheck) +mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badcheck) { return mrb_str_len_to_inum(mrb, str, strlen(str), base, badcheck); } diff --git a/src/variable.c b/src/variable.c index 90efe9e0e..724b153fe 100644 --- a/src/variable.c +++ b/src/variable.c @@ -621,7 +621,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) return ary; } -MRB_API mrb_value +mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) { struct RClass * cls = c; @@ -714,7 +714,7 @@ mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v); } -MRB_API mrb_bool +mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { diff --git a/src/vm.c b/src/vm.c index 7904162be..a381de21f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -593,7 +593,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) * k = Klass.new * k.send :hello, "gentle", "readers" #=> "Hello gentle readers" */ -MRB_API mrb_value +mrb_value mrb_f_send(mrb_state *mrb, mrb_value self) { mrb_sym name; -- cgit v1.2.3 From b8f00e439dd0eaa8282b635bfdaff446ae52d760 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 27 Mar 2019 12:53:24 +0900 Subject: Avoid using 'mrb_str_new_static` if a symbol is packed; fix #4342 --- src/symbol.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 9500e6e36..4d6c20e68 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -325,6 +325,10 @@ mrb_sym_to_s(mrb_state *mrb, mrb_value sym) mrb_int len; p = mrb_sym2name_len(mrb, id, &len); +#ifndef MRB_ENABLE_SYMBOLL_ALL + if (p == mrb->symbuf) + return mrb_str_new(mrb, p, len); +#endif return mrb_str_new_static(mrb, p, len); } -- cgit v1.2.3 From 92dce053ad3432587425ad5b1e4a3cc12b190edc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 27 Mar 2019 17:38:06 +0900 Subject: Fix another bug related to #4342 For short symbols with alpha numeric characters, `mrb_sym2name_len()` returns the same buffer `mrb->symbuf`. Some occasion, we forget the fact that the second call could overwrite the result of first call of the function. We have prepared the static function `sym2name()` which specifies the buffer region for inline packed symbols and use the function in `mrb_sym_to_s`. --- src/symbol.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 4d6c20e68..4cf79046e 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -237,11 +237,11 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) } MRB_API const char* -mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +sym2name(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) { #ifndef MRB_ENABLE_ALL_SYMBOLS if (sym & 1) { /* inline packed symbol */ - return sym_inline_unpack(sym, mrb->symbuf, lenp); + return sym_inline_unpack(sym, buf, lenp); } #endif @@ -255,6 +255,12 @@ mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) return mrb->symtbl[sym].name; } +MRB_API const char* +mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) +{ + return sym2name(mrb, sym, mrb->symbuf, lenp); +} + void mrb_free_symtbl(mrb_state *mrb) { @@ -325,10 +331,9 @@ mrb_sym_to_s(mrb_state *mrb, mrb_value sym) mrb_int len; p = mrb_sym2name_len(mrb, id, &len); -#ifndef MRB_ENABLE_SYMBOLL_ALL - if (p == mrb->symbuf) + if (id&1) { /* inline symbol */ return mrb_str_new(mrb, p, len); -#endif + } return mrb_str_new_static(mrb, p, len); } @@ -545,9 +550,10 @@ sym_cmp(mrb_state *mrb, mrb_value s1) const char *p1, *p2; int retval; mrb_int len, len1, len2; + char buf1[8], buf2[8]; - p1 = mrb_sym2name_len(mrb, sym1, &len1); - p2 = mrb_sym2name_len(mrb, sym2, &len2); + p1 = sym2name(mrb, sym1, buf1, &len1); + p2 = sym2name(mrb, sym2, buf2, &len2); len = lesser(len1, len2); retval = memcmp(p1, p2, len); if (retval == 0) { -- cgit v1.2.3 From 58ca4061b59b35e5fb349aba84754c26939b695c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 27 Mar 2019 19:27:00 +0900 Subject: Remove unused variable in `each_backtrace()` --- src/backtrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/backtrace.c b/src/backtrace.c index 521cd6c1b..efca2562f 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -28,12 +28,12 @@ static const mrb_data_type bt_type = { "Backtrace", mrb_free }; static void each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_func func, void *data) { - ptrdiff_t i, j; + ptrdiff_t i; if (ciidx >= mrb->c->ciend - mrb->c->cibase) ciidx = 10; /* ciidx is broken... */ - for (i=ciidx, j=0; i >= 0; i--,j++) { + for (i=ciidx; i >= 0; i--) { struct backtrace_location loc; mrb_callinfo *ci; mrb_irep *irep; -- cgit v1.2.3 From 21b8d20d7e33bc3d39e8759747f0d82e2f479cd2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 Mar 2019 07:01:34 +0900 Subject: Fixed mistakes in 92dce05 * rename `sym2name` to `sym2name_len`. * `MRB_API` -> `static` --- src/symbol.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 4cf79046e..a7441565a 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -236,8 +236,8 @@ mrb_check_intern_str(mrb_state *mrb, mrb_value str) return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); } -MRB_API const char* -sym2name(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) +static const char* +sym2name_len(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) { #ifndef MRB_ENABLE_ALL_SYMBOLS if (sym & 1) { /* inline packed symbol */ @@ -258,7 +258,7 @@ sym2name(mrb_state *mrb, mrb_sym sym, char *buf, mrb_int *lenp) MRB_API const char* mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) { - return sym2name(mrb, sym, mrb->symbuf, lenp); + return sym2name_len(mrb, sym, mrb->symbuf, lenp); } void @@ -552,8 +552,8 @@ sym_cmp(mrb_state *mrb, mrb_value s1) mrb_int len, len1, len2; char buf1[8], buf2[8]; - p1 = sym2name(mrb, sym1, buf1, &len1); - p2 = sym2name(mrb, sym2, buf2, &len2); + p1 = sym2name_len(mrb, sym1, buf1, &len1); + p2 = sym2name_len(mrb, sym2, buf2, &len2); len = lesser(len1, len2); retval = memcmp(p1, p2, len); if (retval == 0) { -- cgit v1.2.3 From da2bc9e678d9f2cb4d0402701175e303a55308df Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 28 Mar 2019 19:56:51 +0900 Subject: Use `mrb_sym2str` in implementation of `Symbol#to_s` --- src/symbol.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index a7441565a..8ca03344c 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -324,17 +324,9 @@ mrb_init_symtbl(mrb_state *mrb) * :fred.id2name #=> "fred" */ static mrb_value -mrb_sym_to_s(mrb_state *mrb, mrb_value sym) +sym_to_s(mrb_state *mrb, mrb_value sym) { - mrb_sym id = mrb_symbol(sym); - const char *p; - mrb_int len; - - p = mrb_sym2name_len(mrb, id, &len); - if (id&1) { /* inline symbol */ - return mrb_str_new(mrb, p, len); - } - return mrb_str_new_static(mrb, p, len); + return mrb_sym2str(mrb, mrb_symbol(sym)); } /* 15.2.11.3.4 */ @@ -571,13 +563,13 @@ mrb_init_symbol(mrb_state *mrb) { struct RClass *sym; - mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ + mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); mrb_undef_class_method(mrb, sym, "new"); - mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ - mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ - mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ - mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ - mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, sym, "id2name", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ + mrb_define_method(mrb, sym, "to_s", sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ + mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ + mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ + mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); } -- cgit v1.2.3 From 2871d0cdc5e5ef952d27187b5488888bbd18c5b0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 1 Apr 2019 14:13:06 +0900 Subject: Avoid keeping pointers from `mrb_sym2name_len()`; fix #4342 The addresses for packed inline symbols reference `mrb->symbuf` that could be overridden by the later call of `mrb_sym2name_len`. Since file names in call stack information are kept as symbols, keeping the address in the C structures could cause problems like #4342. This changes small incompatible changes in function prototypes: * `mrb_parser_get_filename`: return value changed to `mrb_sym`. * `mrb_debug_get_filename`: add `mrb_state*` as a first argument. * `mrb_debug_get_line`: ditto. I believe above functions are almost internal, and no third-party mrbgem use them. --- include/mruby/compile.h | 4 ++-- include/mruby/debug.h | 5 ++--- mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c | 16 ++++++++------- mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c | 2 +- mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c | 6 +++--- mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c | 4 ++-- mrbgems/mruby-compiler/core/codegen.c | 25 +++++++++++++----------- mrbgems/mruby-compiler/core/parse.y | 20 ++++++++++--------- mrbgems/mruby-proc-ext/src/proc.c | 8 ++++---- src/backtrace.c | 4 ++-- src/class.c | 14 +++---------- src/codedump.c | 14 ++++++------- src/debug.c | 15 +++++++------- src/error.c | 4 ++-- src/load.c | 3 --- src/symbol.c | 9 ++++++++- 16 files changed, 77 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/include/mruby/compile.h b/include/mruby/compile.h index fd735be88..f19d9b0b3 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -118,7 +118,7 @@ struct mrb_parser_state { FILE *f; #endif mrbc_context *cxt; - char const *filename; + mrb_sym filename_sym; int lineno; int column; @@ -168,7 +168,7 @@ MRB_API void mrb_parser_free(struct mrb_parser_state*); MRB_API void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*); MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*); -MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx); +MRB_API mrb_sym mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx); /* utility functions */ #ifndef MRB_DISABLE_STDIO diff --git a/include/mruby/debug.h b/include/mruby/debug.h index f0a40dfcf..e08c47cfc 100644 --- a/include/mruby/debug.h +++ b/include/mruby/debug.h @@ -26,7 +26,6 @@ typedef struct mrb_irep_debug_info_line { typedef struct mrb_irep_debug_info_file { uint32_t start_pos; - const char *filename; mrb_sym filename_sym; uint32_t line_entry_count; mrb_debug_line_type line_type; @@ -47,13 +46,13 @@ typedef struct mrb_irep_debug_info { * get line from irep's debug info and program counter * @return returns NULL if not found */ -MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc); +MRB_API const char *mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc); /* * get line from irep's debug info and program counter * @return returns -1 if not found */ -MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc); +MRB_API int32_t mrb_debug_get_line(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc); MRB_API mrb_irep_debug_info *mrb_debug_info_alloc(mrb_state *mrb, mrb_irep *irep); MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file( diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c index d3ccf08ae..513db4ded 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apibreak.c @@ -84,7 +84,7 @@ free_breakpoint(mrb_state *mrb, mrb_debug_breakpoint *bp) } static uint16_t -check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno) +check_file_lineno(mrb_state *mrb, struct mrb_irep *irep, const char *file, uint16_t lineno) { mrb_irep_debug_info_file *info_file; uint16_t result = 0; @@ -93,8 +93,10 @@ check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno) uint16_t i; for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { + const char *filename; info_file = irep->debug_info->files[f_idx]; - if (!strcmp(info_file->filename, file)) { + filename = mrb_sym2name_len(mrb, info_file->filename_sym, NULL); + if (!strcmp(filename, file)) { result = MRB_DEBUG_BP_FILE_OK; fix_lineno = check_lineno(info_file, lineno); @@ -103,7 +105,7 @@ check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno) } } for (i=0; i < irep->rlen; ++i) { - result |= check_file_lineno(irep->reps[i], file, lineno); + result |= check_file_lineno(mrb, irep->reps[i], file, lineno); if (result == (MRB_DEBUG_BP_FILE_OK | MRB_DEBUG_BP_LINENO_OK)) { return result; } @@ -185,7 +187,7 @@ mrb_debug_set_break_line(mrb_state *mrb, mrb_debug_context *dbg, const char *fil } /* file and lineno check (line type mrb_debug_line_ary only.) */ - result = check_file_lineno(dbg->root_irep, file, lineno); + result = check_file_lineno(mrb, dbg->root_irep, file, lineno); if (result == 0) { return MRB_DEBUG_BREAK_INVALID_FILE; } @@ -426,10 +428,10 @@ mrb_debug_disable_break_all(mrb_state *mrb, mrb_debug_context *dbg) } static mrb_bool -check_start_pc_for_line(mrb_irep *irep, mrb_code *pc, uint16_t line) +check_start_pc_for_line(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, uint16_t line) { if (pc > irep->iseq) { - if (line == mrb_debug_get_line(irep, pc - irep->iseq - 1)) { + if (line == mrb_debug_get_line(mrb, irep, pc - irep->iseq - 1)) { return FALSE; } } @@ -447,7 +449,7 @@ mrb_debug_check_breakpoint_line(mrb_state *mrb, mrb_debug_context *dbg, const ch return MRB_DEBUG_INVALID_ARGUMENT; } - if (!check_start_pc_for_line(dbg->irep, dbg->pc, line)) { + if (!check_start_pc_for_line(mrb, dbg->irep, dbg->pc, line)) { return MRB_DEBUG_OK; } diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c index 21fe64127..66ddfa783 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c @@ -181,7 +181,7 @@ mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, cons else srcname = filename; search_path[0] = srcpath; - search_path[1] = dirname(mrb, mrb_debug_get_filename(mrdb->dbg->irep, 0)); + search_path[1] = dirname(mrb, mrb_debug_get_filename(mrb, mrdb->dbg->irep, 0)); search_path[2] = "."; for (i = 0; i < 3; i++) { diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c index 8e5901754..bc9937e94 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/cmdbreak.c @@ -242,7 +242,7 @@ info_break_select(mrb_state *mrb, mrdb_state *mrdb) } mrb_debug_bptype -parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method) +parse_breakcommand(mrb_state *mrb, mrdb_state *mrdb, const char **file, uint32_t *line, char **cname, char **method) { mrb_debug_context *dbg = mrdb->dbg; char *args; @@ -274,7 +274,7 @@ parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **c STRTOUL(l, body); if (l <= 65535) { *line = l; - *file = (body == args)? mrb_debug_get_filename(dbg->irep, dbg->pc - dbg->irep->iseq): args; + *file = (body == args)? mrb_debug_get_filename(mrb, dbg->irep, dbg->pc - dbg->irep->iseq): args; } else { puts(BREAK_ERR_MSG_RANGEOVER); @@ -332,7 +332,7 @@ dbgcmd_break(mrb_state *mrb, mrdb_state *mrdb) char *method = NULL; int32_t ret; - type = parse_breakcommand(mrdb, &file, &line, &cname, &method); + type = parse_breakcommand(mrb, mrdb, &file, &line, &cname, &method); switch (type) { case MRB_DEBUG_BPTYPE_LINE: ret = mrb_debug_set_break_line(mrb, dbg, file, line); diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c index 5256ac5e3..003406172 100644 --- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c +++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c @@ -569,8 +569,8 @@ mrb_code_fetch_hook(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *reg dbg->xphase = DBG_PHASE_RUNNING; } - file = mrb_debug_get_filename(irep, pc - irep->iseq); - line = mrb_debug_get_line(irep, pc - irep->iseq); + file = mrb_debug_get_filename(mrb, irep, pc - irep->iseq); + line = mrb_debug_get_line(mrb, irep, pc - irep->iseq); switch (dbg->xm) { case DBG_STEP: diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index a2d790e32..927cc3a0f 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -62,7 +62,7 @@ typedef struct scope { struct loopinfo *loop; int ensure_level; - char const *filename; + mrb_sym filename_sym; uint16_t lineno; mrb_code *iseq; @@ -106,8 +106,9 @@ codegen_error(codegen_scope *s, const char *message) s = tmp; } #ifndef MRB_DISABLE_STDIO - if (s->filename && s->lineno) { - fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message); + if (s->filename_sym && s->lineno) { + const char *filename = mrb_sym2name_len(s->mrb, s->filename_sym, NULL); + fprintf(stderr, "codegen error:%s:%d: %s\n", filename, s->lineno, message); } else { fprintf(stderr, "codegen error: %s\n", message); @@ -1399,13 +1400,14 @@ codegen(codegen_scope *s, node *tree, int val) codegen_error(s, "too complex expression"); } if (s->irep && s->filename_index != tree->filename_index) { - const char *filename = mrb_parser_get_filename(s->parser, s->filename_index); + mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index); + const char *filename = mrb_sym2name_len(s->mrb, fname, NULL); mrb_debug_info_append_file(s->mrb, s->irep->debug_info, filename, s->lines, s->debug_start_pos, s->pc); s->debug_start_pos = s->pc; s->filename_index = tree->filename_index; - s->filename = mrb_parser_get_filename(s->parser, tree->filename_index); + s->filename_sym = mrb_parser_get_filename(s->parser, tree->filename_index); } nt = nint(tree->car); @@ -2990,15 +2992,15 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) } p->ai = mrb_gc_arena_save(mrb); - p->filename = prev->filename; - if (p->filename) { + p->filename_sym = prev->filename_sym; + if (p->filename_sym) { p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa); } p->lineno = prev->lineno; /* debug setting */ p->debug_start_pos = 0; - if (p->filename) { + if (p->filename_sym) { mrb_debug_info_alloc(mrb, p->irep); } else { @@ -3026,8 +3028,9 @@ scope_finish(codegen_scope *s) irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen); irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen); irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen); - if (s->filename) { - const char *filename = mrb_parser_get_filename(s->parser, s->filename_index); + if (s->filename_sym) { + mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index); + const char *filename = mrb_sym2name_len(s->mrb, fname, NULL); mrb_debug_info_append_file(s->mrb, s->irep->debug_info, filename, s->lines, s->debug_start_pos, s->pc); @@ -3136,7 +3139,7 @@ generate_code(mrb_state *mrb, parser_state *p, int val) } scope->mrb = mrb; scope->parser = p; - scope->filename = p->filename; + scope->filename_sym = p->filename_sym; scope->filename_index = p->current_filename_index; MRB_TRY(&scope->jmp) { diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 90f01e3a8..88d9ea4ee 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -3162,7 +3162,7 @@ var_ref : variable } | keyword__FILE__ { - const char *fn = p->filename; + const char *fn = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); if (!fn) { fn = "(null)"; } @@ -3671,8 +3671,9 @@ yyerror(parser_state *p, const char *s) if (! p->capture_errors) { #ifndef MRB_DISABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: %s\n", p->filename, p->lineno, p->column, s); + if (p->filename_sym) { + const char *filename = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); + fprintf(stderr, "%s:%d:%d: %s\n", filename, p->lineno, p->column, s); } else { fprintf(stderr, "line %d:%d: %s\n", p->lineno, p->column, s); @@ -3707,8 +3708,9 @@ yywarn(parser_state *p, const char *s) if (! p->capture_errors) { #ifndef MRB_DISABLE_STDIO - if (p->filename) { - fprintf(stderr, "%s:%d:%d: warning: %s\n", p->filename, p->lineno, p->column, s); + if (p->filename_sym) { + const char *filename = mrb_sym2name_len(p->mrb, p->filename_sym, NULL); + fprintf(stderr, "%s:%d:%d: warning: %s\n", filename, p->lineno, p->column, s); } else { fprintf(stderr, "line %d:%d: warning: %s\n", p->lineno, p->column, s); @@ -6012,7 +6014,7 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) mrb_sym* new_table; sym = mrb_intern_cstr(p->mrb, f); - p->filename = mrb_sym2name_len(p->mrb, sym, NULL); + p->filename_sym = sym; p->lineno = (p->filename_table_length > 0)? 0 : 1; for (i = 0; i < p->filename_table_length; ++i) { @@ -6036,11 +6038,11 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) p->filename_table[p->filename_table_length - 1] = sym; } -MRB_API char const* +MRB_API mrb_sym mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { - if (idx >= p->filename_table_length) return NULL; + if (idx >= p->filename_table_length) return 0; else { - return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); + return p->filename_table[idx]; } } diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index 4b85c245d..17884e3c6 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -25,8 +25,8 @@ mrb_proc_source_location(mrb_state *mrb, mrb_value self) int32_t line; const char *filename; - filename = mrb_debug_get_filename(irep, 0); - line = mrb_debug_get_line(irep, 0); + filename = mrb_debug_get_filename(mrb, irep, 0); + line = mrb_debug_get_line(mrb, irep, 0); return (!filename && line == -1)? mrb_nil_value() : mrb_assoc_new(mrb, mrb_str_new_cstr(mrb, filename), mrb_fixnum_value(line)); @@ -46,11 +46,11 @@ mrb_proc_inspect(mrb_state *mrb, mrb_value self) int32_t line; mrb_str_cat_lit(mrb, str, "@"); - filename = mrb_debug_get_filename(irep, 0); + filename = mrb_debug_get_filename(mrb, irep, 0); mrb_str_cat_cstr(mrb, str, filename ? filename : "-"); mrb_str_cat_lit(mrb, str, ":"); - line = mrb_debug_get_line(irep, 0); + line = mrb_debug_get_line(mrb, irep, 0); if (line != -1) { str = mrb_format(mrb, "%S:%S", str, mrb_fixnum_value(line)); } diff --git a/src/backtrace.c b/src/backtrace.c index efca2562f..e4f5a3064 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -58,10 +58,10 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu pc = pc0; } - loc.lineno = mrb_debug_get_line(irep, pc - irep->iseq); + loc.lineno = mrb_debug_get_line(mrb, irep, pc - irep->iseq); if (loc.lineno == -1) continue; - loc.filename = mrb_debug_get_filename(irep, pc - irep->iseq); + loc.filename = mrb_debug_get_filename(mrb, irep, pc - irep->iseq); if (!loc.filename) { loc.filename = "(unknown)"; } diff --git a/src/class.c b/src/class.c index 3354617bb..5c5ee9d17 100644 --- a/src/class.c +++ b/src/class.c @@ -484,15 +484,11 @@ mrb_define_method(mrb_state *mrb, struct RClass *c, const char *name, mrb_func_t MRB_API void mrb_notimplement(mrb_state *mrb) { - const char *str; - mrb_int len; mrb_callinfo *ci = mrb->c->ci; if (ci->mid) { - str = mrb_sym2name_len(mrb, ci->mid, &len); - mrb_raisef(mrb, E_NOTIMP_ERROR, - "%S() function is unimplemented on this machine", - mrb_str_new_static(mrb, str, (size_t)len)); + mrb_value str = mrb_sym2str(mrb, ci->mid); + mrb_raisef(mrb, E_NOTIMP_ERROR, "%S() function is unimplemented on this machine", str); } } @@ -1686,11 +1682,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) } else if (mrb_symbol_p(path)) { /* toplevel class/module */ - const char *str; - mrb_int len; - - str = mrb_sym2name_len(mrb, mrb_symbol(path), &len); - return mrb_str_new(mrb, str, len); + return mrb_sym2str(mrb, mrb_symbol(path)); } return mrb_str_dup(mrb, path); } diff --git a/src/codedump.c b/src/codedump.c index c9c3b25ef..5bffefddb 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -48,11 +48,11 @@ print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b) } static void -print_header(mrb_irep *irep, ptrdiff_t i) +print_header(mrb_state *mrb, mrb_irep *irep, ptrdiff_t i) { int32_t line; - line = mrb_debug_get_line(irep, i); + line = mrb_debug_get_line(mrb, irep, i); if (line < 0) { printf(" "); } @@ -99,12 +99,12 @@ codedump(mrb_state *mrb, mrb_irep *irep) ai = mrb_gc_arena_save(mrb); i = pc - irep->iseq; - next_file = mrb_debug_get_filename(irep, i); + next_file = mrb_debug_get_filename(mrb, irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } - print_header(irep, i); + print_header(mrb, irep, i); ins = READ_B(); switch (ins) { CASE(OP_NOP, Z): @@ -491,7 +491,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT1, Z): ins = READ_B(); printf("OP_EXT1\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i; #include "mruby/ops.h" @@ -501,7 +501,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT2, Z): ins = READ_B(); printf("OP_EXT2\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i; #include "mruby/ops.h" @@ -511,7 +511,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) CASE(OP_EXT3, Z): ins = READ_B(); printf("OP_EXT3\n"); - print_header(irep, pc-irep->iseq-2); + print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i; #include "mruby/ops.h" diff --git a/src/debug.c b/src/debug.c index 2949131e4..0dc02a1e3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -51,20 +51,20 @@ select_line_type(const uint16_t *lines, size_t lines_len) } MRB_API char const* -mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc) +mrb_debug_get_filename(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; if (!irep->debug_info) return NULL; else if ((f = get_file(irep->debug_info, (uint32_t)pc))) { - return f->filename; + return mrb_sym2name_len(mrb, f->filename_sym, NULL); } } return NULL; } MRB_API int32_t -mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc) +mrb_debug_get_line(mrb_state *mrb, mrb_irep *irep, ptrdiff_t pc) { if (irep && pc >= 0 && pc < irep->ilen) { mrb_irep_debug_info_file* f = NULL; @@ -129,7 +129,6 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, mrb_irep_debug_info_file *f; uint32_t file_pc_count; size_t fn_len; - mrb_int len; uint32_t i; if (!d) return NULL; @@ -138,8 +137,10 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, mrb_assert(filename); mrb_assert(lines); - if (d->flen > 0 && strcmp(filename, d->files[d->flen - 1]->filename) == 0) { - return NULL; + if (d->flen > 0) { + const char *fn = mrb_sym2name_len(mrb, d->files[d->flen - 1]->filename_sym, NULL); + if (strcmp(filename, fn) == 0) + return NULL; } f = (mrb_irep_debug_info_file*)mrb_malloc(mrb, sizeof(*f)); @@ -156,8 +157,6 @@ mrb_debug_info_append_file(mrb_state *mrb, mrb_irep_debug_info *d, fn_len = strlen(filename); f->filename_sym = mrb_intern(mrb, filename, fn_len); - len = 0; - f->filename = mrb_sym2name_len(mrb, f->filename_sym, &len); f->line_type = select_line_type(lines + start_pos, end_pos - start_pos); f->lines.ptr = NULL; diff --git a/src/error.c b/src/error.c index 50d1ab6f9..e69812dda 100644 --- a/src/error.c +++ b/src/error.c @@ -208,8 +208,8 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc) if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) { mrb_irep *irep = ci->proc->body.irep; - int32_t const line = mrb_debug_get_line(irep, err - irep->iseq); - char const* file = mrb_debug_get_filename(irep, err - irep->iseq); + int32_t const line = mrb_debug_get_line(mrb, irep, err - irep->iseq); + char const* file = mrb_debug_get_filename(mrb, irep, err - irep->iseq); if (line != -1 && file) { mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file)); mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line)); diff --git a/src/load.c b/src/load.c index 55e0845f3..ab0346750 100644 --- a/src/load.c +++ b/src/load.c @@ -317,7 +317,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) { mrb_irep_debug_info_file *file; uint16_t filename_idx; - mrb_int len; file = (mrb_irep_debug_info_file *)mrb_malloc(mrb, sizeof(*file)); irep->debug_info->files[f_idx] = file; @@ -330,8 +329,6 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t * bin += sizeof(uint16_t); mrb_assert(filename_idx < filenames_len); file->filename_sym = filenames[filename_idx]; - len = 0; - file->filename = mrb_sym2name_len(mrb, file->filename_sym, &len); file->line_entry_count = bin_to_uint32(bin); bin += sizeof(uint32_t); diff --git a/src/symbol.c b/src/symbol.c index 8ca03344c..96ca9dd17 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -520,7 +520,14 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) return name; } else { - mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len)); + mrb_value str; + if (sym&1) { /* inline symbol */ + str = mrb_str_new(mrb, name, len); + } + else { + str = mrb_str_new_static(mrb, name, len); + } + str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } } -- cgit v1.2.3 From 55cb625808ab9b498d42d13442f5ce5115d606a5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 1 Apr 2019 19:49:30 +0900 Subject: Fix modifiable class name Fix the following example: Object.const_set :A, Module.new{const_set :B, Class.new} ab = A::B.to_s p ab #=> "A::B" # Good ab[0] = "x" p A::B.to_s #=> "x::B" # Bad --- src/variable.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 724b153fe..9edfb32bd 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1106,6 +1106,7 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + path = mrb_str_dup(mrb, path); } return path; } -- cgit v1.2.3 From abc6c990a636058f41f9d34f12451036cb9c89fd Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 18:54:25 +0900 Subject: Remove unnecessary `_set_output_format` call Three-digit exponent issue was fixed via another workaround (63b8f5c). --- src/state.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/state.c b/src/state.c index c3ce1dc33..08d7ba906 100644 --- a/src/state.c +++ b/src/state.c @@ -42,10 +42,6 @@ mrb_open_core(mrb_allocf f, void *ud) mrb_init_core(mrb); -#if !defined(MRB_DISABLE_STDIO) && defined(_MSC_VER) && _MSC_VER < 1900 - _set_output_format(_TWO_DIGIT_EXPONENT); -#endif - return mrb; } -- cgit v1.2.3 From 5e0caefa58bb0fae4174858abb3ba8cd7ccf7058 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Apr 2019 19:25:06 +0900 Subject: Modify `#else` and `#endif` annotations in `src/fmt_fp.c` [ci skip] --- src/fmt_fp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/fmt_fp.c b/src/fmt_fp.c index 14c74ef9e..1f1af6764 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -372,7 +372,7 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) } return f.str; } -#else /* MRB_DISABLE_STDIO */ +#else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #include #include @@ -384,5 +384,5 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); return mrb_str_new_cstr(mrb, buf); } -#endif /* MRB_DISABLE_STDIO */ +#endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #endif -- cgit v1.2.3 From ed41bbb199fb614bb68423d19d26c09c5027319a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 4 Apr 2019 22:17:26 +0900 Subject: Use `mrb_proc_arity` instead of `Proc#arity` call in `Method#arity` --- include/mruby/proc.h | 1 + mrbgems/mruby-method/src/method.c | 15 ++------- src/proc.c | 69 +++++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/include/mruby/proc.h b/include/mruby/proc.h index 021f9c117..a8b16db1d 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -86,6 +86,7 @@ struct RProc *mrb_closure_new(mrb_state*, mrb_irep*); MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t); MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals); void mrb_proc_copy(struct RProc *a, struct RProc *b); +mrb_int mrb_proc_arity(const struct RProc *p); /* implementation of #send method */ mrb_value mrb_f_send(mrb_state *mrb, mrb_value self); diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index fa8985694..9f1134227 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -212,19 +212,8 @@ static mrb_value method_arity(mrb_state *mrb, mrb_value self) { mrb_value proc = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "proc")); - struct RProc *rproc; - struct RClass *orig; - mrb_value ret; - - if (mrb_nil_p(proc)) - return mrb_fixnum_value(-1); - - rproc = mrb_proc_ptr(proc); - orig = rproc->c; - rproc->c = mrb->proc_class; - ret = mrb_funcall(mrb, proc, "arity", 0); - rproc->c = orig; - return ret; + mrb_int arity = mrb_nil_p(proc) ? -1 : mrb_proc_arity(mrb_proc_ptr(proc)); + return mrb_fixnum_value(arity); } static mrb_value diff --git a/src/proc.c b/src/proc.c index dab95e465..bf3f01504 100644 --- a/src/proc.c +++ b/src/proc.c @@ -221,38 +221,9 @@ mrb_proc_cfunc_p(struct RProc *p) /* 15.2.17.4.2 */ static mrb_value -mrb_proc_arity(mrb_state *mrb, mrb_value self) +proc_arity(mrb_state *mrb, mrb_value self) { - struct RProc *p = mrb_proc_ptr(self); - struct mrb_irep *irep; - mrb_code *pc; - mrb_aspec aspec; - int ma, op, ra, pa, arity; - - if (MRB_PROC_CFUNC_P(p)) { - /* TODO cfunc aspec not implemented yet */ - return mrb_fixnum_value(-1); - } - - irep = p->body.irep; - if (!irep) { - return mrb_fixnum_value(0); - } - - pc = irep->iseq; - /* arity is depend on OP_ENTER */ - if (*pc != OP_ENTER) { - return mrb_fixnum_value(0); - } - - aspec = PEEK_W(pc+1); - ma = MRB_ASPEC_REQ(aspec); - op = MRB_ASPEC_OPT(aspec); - ra = MRB_ASPEC_REST(aspec); - pa = MRB_ASPEC_POST(aspec); - arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; - - return mrb_fixnum_value(arity); + return mrb_fixnum_value(mrb_proc_arity(mrb_proc_ptr(self))); } /* 15.3.1.2.6 */ @@ -287,6 +258,40 @@ proc_lambda(mrb_state *mrb, mrb_value self) return blk; } +mrb_int +mrb_proc_arity(const struct RProc *p) +{ + struct mrb_irep *irep; + mrb_code *pc; + mrb_aspec aspec; + int ma, op, ra, pa, arity; + + if (MRB_PROC_CFUNC_P(p)) { + /* TODO cfunc aspec not implemented yet */ + return -1; + } + + irep = p->body.irep; + if (!irep) { + return 0; + } + + pc = irep->iseq; + /* arity is depend on OP_ENTER */ + if (*pc != OP_ENTER) { + return 0; + } + + aspec = PEEK_W(pc+1); + ma = MRB_ASPEC_REQ(aspec); + op = MRB_ASPEC_OPT(aspec); + ra = MRB_ASPEC_REST(aspec); + pa = MRB_ASPEC_POST(aspec); + arity = ra || (MRB_PROC_STRICT_P(p) && op) ? -(ma + pa + 1) : ma + pa; + + return arity; +} + void mrb_init_proc(mrb_state *mrb) { @@ -303,7 +308,7 @@ mrb_init_proc(mrb_state *mrb) mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_NONE()|MRB_ARGS_BLOCK()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); + mrb_define_method(mrb, mrb->proc_class, "arity", proc_arity, MRB_ARGS_NONE()); p = mrb_proc_new(mrb, call_irep); MRB_METHOD_FROM_PROC(m, p); -- cgit v1.2.3 From 623e15936a6c8b8ecaf9dca341be80c9316fd8be Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 5 Apr 2019 19:03:46 +0900 Subject: `Module#alias_method` should return `self` in ISO standard --- src/class.c | 2 +- test/t/module.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 5c5ee9d17..eaef787f7 100644 --- a/src/class.c +++ b/src/class.c @@ -1843,7 +1843,7 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "nn", &new_name, &old_name); mrb_alias_method(mrb, c, new_name, old_name); - return mrb_nil_value(); + return mod; } void diff --git a/test/t/module.rb b/test/t/module.rb index ec36855e8..da0f78fad 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -25,6 +25,17 @@ assert('Module', '15.2.2') do assert_equal Class, Module.class end +assert('Module#alias_method', '15.2.2.4.8') do + cls = Class.new do + def foo + "FOO" + end + end + + assert_same(cls, cls.alias_method(:bar, :foo)) + assert_equal("FOO", cls.new.bar) +end + # TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do assert('Module#ancestors', '15.2.2.4.9') do -- cgit v1.2.3 From 271a91c64815900338f0f9c152f9f3dabab8246d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Apr 2019 16:32:27 +0900 Subject: Remove unused `mrb_proc_cfunc_p()` --- src/proc.c | 6 ------ src/vm.c | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/proc.c b/src/proc.c index bf3f01504..094fff816 100644 --- a/src/proc.c +++ b/src/proc.c @@ -213,12 +213,6 @@ mrb_proc_init_copy(mrb_state *mrb, mrb_value self) return self; } -int -mrb_proc_cfunc_p(struct RProc *p) -{ - return MRB_PROC_CFUNC_P(p); -} - /* 15.2.17.4.2 */ static mrb_value proc_arity(mrb_state *mrb, mrb_value self) diff --git a/src/vm.c b/src/vm.c index a381de21f..60d5dee14 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1004,7 +1004,7 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); MRB_API mrb_value mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) { - /* mrb_assert(mrb_proc_cfunc_p(proc)) */ + /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */ mrb_code *pc0 = pc; mrb_irep *irep = proc->body.irep; mrb_value *pool = irep->pool; -- cgit v1.2.3 From 5adef8ba44b92ca01692451e21af5c3f47e8853c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Apr 2019 17:40:51 +0900 Subject: Move `Array#(append|prepend)` from core to `mruby-ary-ext` They are not included in ISO standard. --- mrbgems/mruby-array-ext/mrblib/array.rb | 3 +++ src/array.c | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 387bd6c90..59b6087d2 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -936,4 +936,7 @@ class Array end h end + + alias append push + alias prepend unshift end diff --git a/src/array.c b/src/array.c index 707820ab9..43f4c98b5 100644 --- a/src/array.c +++ b/src/array.c @@ -1286,7 +1286,6 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ - mrb_define_method(mrb, a, "append", mrb_ary_push_m, MRB_ARGS_ANY()); mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ @@ -1295,7 +1294,6 @@ mrb_init_array(mrb_state *mrb) mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ - mrb_define_method(mrb, a, "prepend", mrb_ary_unshift_m, MRB_ARGS_ANY()); mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 6cec0c9f62c176e9bd926d12551b384315e98388 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Apr 2019 19:02:45 +0900 Subject: Fix C99 style inline declaration; fix #4365 --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 4128ea3a6..742df7b76 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -207,12 +207,12 @@ flo_to_s(mrb_state *mrb, mrb_value flt) char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; mrb_value str = mrb_float_to_str(mrb, flt, fmt); mrb_int len; - char *begp; + char *begp, *p, *endp; insert_dot_zero: begp = RSTRING_PTR(str); len = RSTRING_LEN(str); - for (char *p = begp, *endp = p + len; p < endp; ++p) { + for (p = begp, endp = p + len; p < endp; ++p) { if (*p == '.') { return str; } -- cgit v1.2.3 From e3beef065c2de80a843f329599b424676d83086c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Apr 2019 18:23:11 +0900 Subject: Extract frozen checking to function --- include/mruby.h | 6 ++++++ mrbgems/mruby-struct/src/struct.c | 5 +---- src/array.c | 4 +--- src/class.c | 7 +------ src/error.c | 7 +++++++ src/hash.c | 5 +---- src/string.c | 12 ++---------- src/variable.c | 4 +--- 8 files changed, 20 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 5b0d84cd3..939601b4d 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1143,6 +1143,7 @@ MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc); MRB_API mrb_noreturn void mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg); MRB_API mrb_noreturn void mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...); MRB_API mrb_noreturn void mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...); +MRB_API mrb_noreturn void mrb_frozen_error(mrb_state *mrb, void *frozen_obj); MRB_API void mrb_warn(mrb_state *mrb, const char *fmt, ...); MRB_API mrb_noreturn void mrb_bug(mrb_state *mrb, const char *fmt, ...); MRB_API void mrb_print_backtrace(mrb_state *mrb); @@ -1196,6 +1197,11 @@ MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); +static inline void mrb_check_frozen(mrb_state *mrb, void *o) +{ + if (MRB_FROZEN_P((struct RBasic*)o)) mrb_frozen_error(mrb, o); +} + typedef enum call_type { CALL_PUBLIC, CALL_FCALL, diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index c0ce71219..1df135a9f 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -87,10 +87,7 @@ mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass) static void mrb_struct_modify(mrb_state *mrb, mrb_value strct) { - if (MRB_FROZEN_P(mrb_basic_ptr(strct))) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen struct"); - } - + mrb_check_frozen(mrb, mrb_basic_ptr(strct)); mrb_write_barrier(mrb, mrb_basic_ptr(strct)); } diff --git a/src/array.c b/src/array.c index 43f4c98b5..d4302cb22 100644 --- a/src/array.c +++ b/src/array.c @@ -120,9 +120,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify_check(mrb_state *mrb, struct RArray *a) { - if (MRB_FROZEN_P(a)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen array"); - } + mrb_check_frozen(mrb, a); } static void diff --git a/src/class.c b/src/class.c index eaef787f7..fd56fa399 100644 --- a/src/class.c +++ b/src/class.c @@ -441,12 +441,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_ MRB_CLASS_ORIGIN(c); h = c->mt; - if (MRB_FROZEN_P(c)) { - if (c->tt == MRB_TT_MODULE) - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen module"); - else - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen class"); - } + mrb_check_frozen(mrb, c); if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = m; diff --git a/src/error.c b/src/error.c index e69812dda..4c1b67c99 100644 --- a/src/error.c +++ b/src/error.c @@ -484,6 +484,13 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, mrb_exc_raise(mrb, exc); } +MRB_API mrb_noreturn void +mrb_frozen_error(mrb_state *mrb, void *frozen_obj) +{ + mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", + mrb_obj_value(mrb_class(mrb, mrb_obj_value(frozen_obj)))); +} + void mrb_init_exception(mrb_state *mrb) { diff --git a/src/hash.c b/src/hash.c index fd963c3de..c4820513b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -746,10 +746,7 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { - if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen hash"); - } - + mrb_check_frozen(mrb, mrb_hash_ptr(hash)); if (!RHASH_TBL(hash)) { RHASH_TBL(hash) = ht_new(mrb); } diff --git a/src/string.c b/src/string.c index 63c592d59..f7a805a94 100644 --- a/src/string.c +++ b/src/string.c @@ -493,20 +493,12 @@ str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset) return mrb_str_index(mrb, str, ptr, len, offset); } -static void -check_frozen(mrb_state *mrb, struct RString *s) -{ - if (MRB_FROZEN_P(s)) { - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen string"); - } -} - static mrb_value str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) { mrb_int len; - check_frozen(mrb, s1); + mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); s1->flags &= ~MRB_STR_NO_UTF; s1->flags |= s2->flags&MRB_STR_NO_UTF; @@ -646,7 +638,7 @@ mrb_locale_from_utf8(const char *utf8, int len) MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { - check_frozen(mrb, s); + mrb_check_frozen(mrb, s); s->flags &= ~MRB_STR_NO_UTF; if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; diff --git a/src/variable.c b/src/variable.c index 9edfb32bd..cf89a4a02 100644 --- a/src/variable.c +++ b/src/variable.c @@ -346,9 +346,7 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t; - if (MRB_FROZEN_P(obj)) { - mrb_raisef(mrb, E_FROZEN_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); - } + mrb_check_frozen(mrb, obj); assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); -- cgit v1.2.3 From 16f86f8ede2f0d33fdd642d734c796b9435a57bf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 05:42:36 +0900 Subject: Use the old style declaration; ref #4365 --- src/variable.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 9edfb32bd..02e4f38a1 100644 --- a/src/variable.c +++ b/src/variable.c @@ -1116,7 +1116,9 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) mrb_bool mrb_ident_p(const char *s, mrb_int len) { - for (mrb_int i = 0; i < len; i++) { + mrb_int i; + + for (i = 0; i < len; i++) { if (!identchar(s[i])) return FALSE; } return TRUE; -- cgit v1.2.3 From 88ac7549c08411b8d96a7ed0ed8ab2299228f28f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 17:14:08 +0900 Subject: Remove `MRB_API` from `mrb_instance_new`. --- include/mruby.h | 2 -- include/mruby/class.h | 1 + src/class.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index e567e1da4..7026c1f5e 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -570,8 +570,6 @@ MRB_INLINE mrb_value mrb_class_new_instance(mrb_state *mrb, mrb_int argc, const return mrb_obj_new(mrb,c,argc,argv); } -MRB_API mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); - /** * Creates a new instance of Class, Class. * diff --git a/include/mruby/class.h b/include/mruby/class.h index b667e2051..5ac6e5c40 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -85,6 +85,7 @@ MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym); MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym); MRB_API struct RClass* mrb_class_real(struct RClass* cl); +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym); mrb_value mrb_class_find_path(mrb_state*, struct RClass*); diff --git a/src/class.c b/src/class.c index fd56fa399..6f6b3feda 100644 --- a/src/class.c +++ b/src/class.c @@ -1498,7 +1498,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * */ -MRB_API mrb_value +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv) { mrb_value obj, blk; -- cgit v1.2.3 From 4776ac50ed39652e56a084475a5d79c1bbccc6c0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 10 Apr 2019 19:07:22 +0900 Subject: Remove too aggressive `initialize` call in `mrb_instance_new`. --- src/class.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 6f6b3feda..d6efdbdc4 100644 --- a/src/class.c +++ b/src/class.c @@ -1505,22 +1505,13 @@ mrb_instance_new(mrb_state *mrb, mrb_value cv) mrb_value *argv; mrb_int argc; mrb_sym init; - mrb_method_t m; mrb_get_args(mrb, "*&", &argv, &argc, &blk); obj = mrb_instance_alloc(mrb, cv); init = mrb_intern_lit(mrb, "initialize"); - m = mrb_method_search(mrb, mrb_class(mrb, obj), init); - if (MRB_METHOD_CFUNC_P(m)) { - mrb_func_t f = MRB_METHOD_CFUNC(m); - if (f != mrb_bob_init) { - f(mrb, obj); - } - } - else { + if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) { mrb_funcall_with_block(mrb, obj, init, argc, argv, blk); } - return obj; } -- cgit v1.2.3 From 7b0ebed033777cd8bdb8e3668e5c49cfe1b69c5d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 10 Apr 2019 19:17:00 +0900 Subject: Use `mrb_immediate_p()` in `mrb_obj_freeze()` and `mrb_obj_frozen()` --- src/etc.c | 2 ++ src/kernel.c | 44 ++++++-------------------------------------- test/t/kernel.rb | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/etc.c b/src/etc.c index 12d948a55..6c5fb7480 100644 --- a/src/etc.c +++ b/src/etc.c @@ -167,6 +167,7 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) v.value.p = mrb_obj_alloc(mrb, MRB_TT_FLOAT, mrb->float_class); v.value.fp->f = f; + MRB_SET_FROZEN_FLAG(v.value.bp); return v; } @@ -177,6 +178,7 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) nf->tt = MRB_TT_FLOAT; nf->c = mrb->float_class; nf->f = f; + MRB_SET_FROZEN_FLAG(nf); return mrb_obj_value(nf); } #endif /* MRB_WITHOUT_FLOAT */ diff --git a/src/kernel.c b/src/kernel.c index 7890e3dac..d9a1d36ce 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -434,24 +434,11 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_freeze(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return self; - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - MRB_SET_FROZEN_FLAG(b); + if (!mrb_immediate_p(self)) { + struct RBasic *b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + } } return self; } @@ -459,26 +446,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_frozen(mrb_state *mrb, mrb_value self) { - struct RBasic *b; - - switch (mrb_type(self)) { - case MRB_TT_FALSE: - case MRB_TT_TRUE: - case MRB_TT_FIXNUM: - case MRB_TT_SYMBOL: -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: -#endif - return mrb_true_value(); - default: - break; - } - - b = mrb_basic_ptr(self); - if (!MRB_FROZEN_P(b)) { - return mrb_false_value(); - } - return mrb_true_value(); + return mrb_bool_value(mrb_immediate_p(self) || MRB_FROZEN_P(mrb_basic_ptr(self))); } /* 15.3.1.3.15 */ diff --git a/test/t/kernel.rb b/test/t/kernel.rb index d99358c0c..bf7dbe94c 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -247,6 +247,23 @@ assert('Kernel#freeze') do assert_equal obj, obj.freeze assert_equal 0, 0.freeze assert_equal :a, :a.freeze + assert_equal true, true.freeze + assert_equal false, false.freeze + assert_equal nil, nil.freeze + skip unless Object.const_defined?(:Float) + assert_equal 0.0, 0.0.freeze +end + +assert('Kernel#frozen?') do + assert_false "".frozen? + assert_true "".freeze.frozen? + assert_true 0.frozen? + assert_true :a.frozen? + assert_true true.frozen? + assert_true false.frozen? + assert_true nil.frozen? + skip unless Object.const_defined?(:Float) + assert_true 0.0.frozen? end assert('Kernel#global_variables', '15.3.1.3.14') do -- cgit v1.2.3 From 0c9c3f08ee2c62f6f1b4ce9968a4d12e2ea60276 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 11 Apr 2019 21:42:18 +0900 Subject: Remove incorrect flags updating in `mrb_regexp_p()` --- src/etc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/etc.c b/src/etc.c index 6c5fb7480..d15b398dd 100644 --- a/src/etc.c +++ b/src/etc.c @@ -205,7 +205,6 @@ mrb_regexp_p(mrb_state *mrb, mrb_value v) return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); } else { - mrb->flags |= MRB_STATE_REGEXP; mrb->flags |= MRB_STATE_NO_REGEXP; } return FALSE; -- cgit v1.2.3 From 79fd986bcb2c6bc056a08669664c0024d77725f9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 12 Apr 2019 23:03:38 +0900 Subject: Small refactoring in `mrb_funcall_with_block`. --- src/vm.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 60d5dee14..6bd9d53f9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -486,6 +486,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = (int)argc; ci->target_class = c; mrb->c->stack = mrb->c->stack + n; + if (argc < 0) argc = 1; if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; } @@ -500,11 +501,10 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->argc = -1; argc = 1; } - else { + else if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); ci->proc = p; - if (argc < 0) argc = 1; mrb_stack_extend(mrb, p->body.irep->nregs + argc); } if (voff >= 0) { @@ -520,9 +520,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc int ai = mrb_gc_arena_save(mrb); ci->acc = CI_ACC_DIRECT; - if (MRB_METHOD_PROC_P(m)) { - ci->proc = MRB_METHOD_PROC(m); - } val = MRB_METHOD_CFUNC(m)(mrb, self); mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); -- cgit v1.2.3 From f639da0f1c32c20255c32821191697d35350c1ad Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 13 Apr 2019 18:16:28 +0900 Subject: Fix broken NaN with `MRB_NAN_BOXING` Example: $ bin/mruby -e '(Float::INFINITY - Float::INFINITY).nan?' zsh: segmentation fault Cause: `SET_FLOAT_VALUE` is not used. It is needed for normalizing NaN. Treatment: In my environment, this issue could be reproduced only when `infinity - infinity`, however `SET_FLOAT_VALUE` should be used in all arithmetic operations (regardless of boxing setting), I think. So I fixed all similar codes by extracting to macro. --- src/vm.c | 96 +++++++++++----------------------------------------------------- 1 file changed, 16 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 6bd9d53f9..712d39b66 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2214,9 +2214,13 @@ RETRY_TRY_BLOCK: } #define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) -#define OP_MATH_BODY(op,v1,v2) do {\ - v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\ -} while(0) +#define OP_MATH_FLOAT_BODY(op,t1,t2) do { \ + RETURN_TYPE_OF_##t1 x = t1(regs[a]); \ + RETURN_TYPE_OF_##t2 y = t2(regs[a+1]); \ + SET_FLOAT_VALUE(mrb, regs[a], x op y); \ +} while (0) +#define RETURN_TYPE_OF_mrb_fixnum mrb_int +#define RETURN_TYPE_OF_mrb_float mrb_float CASE(OP_ADD, B) { /* need to check if op is overridden */ @@ -2239,33 +2243,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y); - } + OP_MATH_FLOAT_BODY(+,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } -#else - OP_MATH_BODY(+,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(+,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x + y); - } -#else - OP_MATH_BODY(+,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(+,mrb_float,mrb_float); break; #endif case TYPES2(MRB_TT_STRING,MRB_TT_STRING): @@ -2300,33 +2284,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y); - } + OP_MATH_FLOAT_BODY(-,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(-,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x - y); - } -#else - OP_MATH_BODY(-,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(-,mrb_float,mrb_float); break; #endif default: @@ -2357,33 +2321,13 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y); - } + OP_MATH_FLOAT_BODY(*,mrb_fixnum,mrb_float); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_fixnum); -#endif + OP_MATH_FLOAT_BODY(*,mrb_float,mrb_fixnum); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x * y); - } -#else - OP_MATH_BODY(*,mrb_float,mrb_float); -#endif + OP_MATH_FLOAT_BODY(*,mrb_float,mrb_float); break; #endif default: @@ -2466,14 +2410,10 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); SET_FLOAT_VALUE(mrb, regs[a], x + b); } -#else - mrb_float(regs[a]) += b; -#endif break; #endif default: @@ -2507,14 +2447,10 @@ RETRY_TRY_BLOCK: break; #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING { mrb_float x = mrb_float(regs[a]); SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); } -#else - mrb_float(regs_a[0]) -= b; -#endif break; #endif default: -- cgit v1.2.3 From 0ebbc491a1ce45b85934be04e5824d69463ca593 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 15:35:51 +0900 Subject: Include `RFiber` and `RIstruct` as a part of `RVALUE` --- src/gc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index ec52787e8..798e2c00a 100644 --- a/src/gc.c +++ b/src/gc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -109,8 +110,10 @@ typedef struct { struct RHash hash; struct RRange range; struct RData data; + struct RIstruct istruct; struct RProc proc; struct REnv env; + struct RFiber fiber; struct RException exc; struct RBreak brk; #ifdef MRB_WORD_BOXING -- cgit v1.2.3 From 3f3e4754d931004838278c1483e047a3635ebeb0 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 15:58:11 +0900 Subject: Fix leaked function symbols - `free_heap()` in src/gc.c - `symhash()` in src/symbol.c - `no_optimize()` in mrbgems/mruby-compiler/core/codegen.c --- mrbgems/mruby-compiler/core/codegen.c | 3 +-- src/gc.c | 2 +- src/symbol.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index b6d35f363..ed8fc3150 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -273,8 +273,7 @@ genop_W(codegen_scope *s, mrb_code i, uint32_t a) #define NOVAL 0 #define VAL 1 -//static -mrb_bool +static mrb_bool no_optimize(codegen_scope *s) { if (s && s->parser && s->parser->no_optimize) diff --git a/src/gc.c b/src/gc.c index ec52787e8..d07335eca 100644 --- a/src/gc.c +++ b/src/gc.c @@ -396,7 +396,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc) static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); -void +static void free_heap(mrb_state *mrb, mrb_gc *gc) { mrb_heap_page *page = gc->heaps; diff --git a/src/symbol.c b/src/symbol.c index 96ca9dd17..b26f2b1fd 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -91,7 +91,7 @@ sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) } #endif -uint8_t +static uint8_t symhash(const char *key, size_t len) { uint32_t hash, i; -- cgit v1.2.3 From d557f977324bc55ae99205608099a788038712d6 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:39:50 +0900 Subject: Remove pointer check after `mrb_malloc()` --- src/variable.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index f97b09c52..6899d7475 100644 --- a/src/variable.c +++ b/src/variable.c @@ -87,7 +87,6 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) } seg = (segment*)mrb_malloc(mrb, sizeof(segment)); - if (!seg) return; seg->next = NULL; seg->key[0] = sym; seg->val[0] = val; -- cgit v1.2.3 From d8527d17ea504aebcdbd3970127899e0216d46dc Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:42:35 +0900 Subject: Fix wrong size of instance variable if occur out of memory --- src/variable.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 6899d7475..983fe52f7 100644 --- a/src/variable.c +++ b/src/variable.c @@ -79,10 +79,10 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) } /* Not found */ - t->size++; if (matched_seg) { matched_seg->key[matched_idx] = sym; matched_seg->val[matched_idx] = val; + t->size++; return; } @@ -91,6 +91,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) seg->key[0] = sym; seg->val[0] = val; t->last_len = 1; + t->size++; if (prev) { prev->next = seg; } -- cgit v1.2.3 From d328808892bf866f9ad72ba476fcee00edd06293 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Apr 2019 17:55:20 +0900 Subject: Fix memory leak for hash table index if occur out of memory --- src/hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index c4820513b..a9367a426 100644 --- a/src/hash.c +++ b/src/hash.c @@ -182,7 +182,7 @@ ht_index(mrb_state *mrb, htable *t) if (!index || index->capa < size) { index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size); if (index == NULL) { - mrb_free(mrb, index); + mrb_free(mrb, t->index); t->index = NULL; return; } -- cgit v1.2.3 From 30c880bea9ace559ccef50d5ed1a5dbf75659bbf Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 14 Apr 2019 22:40:17 +0900 Subject: Extract similar codes to macros for math opcode in `mrb_vm_exec` --- src/vm.c | 269 +++++++++++++++++++++------------------------------------------ 1 file changed, 89 insertions(+), 180 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 712d39b66..a7ecc575d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2214,128 +2214,67 @@ RETRY_TRY_BLOCK: } #define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff)) -#define OP_MATH_FLOAT_BODY(op,t1,t2) do { \ - RETURN_TYPE_OF_##t1 x = t1(regs[a]); \ - RETURN_TYPE_OF_##t2 y = t2(regs[a+1]); \ - SET_FLOAT_VALUE(mrb, regs[a], x op y); \ -} while (0) -#define RETURN_TYPE_OF_mrb_fixnum mrb_int -#define RETURN_TYPE_OF_mrb_float mrb_float +#define OP_MATH(op_name) \ + /* need to check if op is overridden */ \ + switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { \ + OP_MATH_CASE_FIXNUM(op_name); \ + OP_MATH_CASE_FLOAT(op_name, fixnum, float); \ + OP_MATH_CASE_FLOAT(op_name, float, fixnum); \ + OP_MATH_CASE_FLOAT(op_name, float, float); \ + OP_MATH_CASE_STRING_##op_name(); \ + default: \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATH_CASE_FIXNUM(op_name) \ + case TYPES2(MRB_TT_FIXNUM, MRB_TT_FIXNUM): \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = mrb_fixnum(regs[a+1]), z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) (void)0 +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) SET_INT_VALUE(regs[a], z) +#else +#define OP_MATH_CASE_FLOAT(op_name, t1, t2) \ + case TYPES2(OP_MATH_TT_##t1, OP_MATH_TT_##t2): \ + { \ + mrb_float z = mrb_##t1(regs[a]) OP_MATH_OP_##op_name mrb_##t2(regs[a+1]); \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break +#define OP_MATH_OVERFLOW_INT(op_name, x, y, z) \ + SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x OP_MATH_OP_##op_name (mrb_float)y) +#endif +#define OP_MATH_CASE_STRING_add() \ + case TYPES2(MRB_TT_STRING, MRB_TT_STRING): \ + regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); \ + mrb_gc_arena_restore(mrb, ai); \ + break +#define OP_MATH_CASE_STRING_sub() (void)0 +#define OP_MATH_CASE_STRING_mul() (void)0 +#define OP_MATH_OP_add + +#define OP_MATH_OP_sub - +#define OP_MATH_OP_mul * +#define OP_MATH_TT_fixnum MRB_TT_FIXNUM +#define OP_MATH_TT_float MRB_TT_FLOAT CASE(OP_ADD, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - mrb_value *regs_a = regs + a; - - x = mrb_fixnum(regs_a[0]); - y = mrb_fixnum(regs_a[1]); - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(+,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(+,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(+,mrb_float,mrb_float); - break; -#endif - case TYPES2(MRB_TT_STRING,MRB_TT_STRING): - regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); - break; - default: - c = 1; - mid = mrb_intern_lit(mrb, "+"); - goto L_SEND_SYM; - } - mrb_gc_arena_restore(mrb, ai); - NEXT; + OP_MATH(add); } CASE(OP_SUB, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(-,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(-,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(-,mrb_float,mrb_float); - break; -#endif - default: - c = 1; - mid = mrb_intern_lit(mrb, "-"); - goto L_SEND_SYM; - } - NEXT; + OP_MATH(sub); } CASE(OP_MUL, B) { - /* need to check if op is overridden */ - switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): - { - mrb_int x, y, z; - - x = mrb_fixnum(regs[a]); - y = mrb_fixnum(regs[a+1]); - if (mrb_int_mul_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(*,mrb_fixnum,mrb_float); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): - OP_MATH_FLOAT_BODY(*,mrb_float,mrb_fixnum); - break; - case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): - OP_MATH_FLOAT_BODY(*,mrb_float,mrb_float); - break; -#endif - default: - c = 1; - mid = mrb_intern_lit(mrb, "*"); - goto L_SEND_SYM; - } - NEXT; + OP_MATH(mul); } CASE(OP_DIV, B) { @@ -2390,76 +2329,46 @@ RETRY_TRY_BLOCK: NEXT; } - CASE(OP_ADDI, BB) { - /* need to check if + is overridden */ - switch (mrb_type(regs[a])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_int y = (mrb_int)b; - mrb_int z; - - if (mrb_int_add_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs[a], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], x + b); - } - break; +#define OP_MATHI(op_name) \ + /* need to check if op is overridden */ \ + switch (mrb_type(regs[a])) { \ + OP_MATHI_CASE_FIXNUM(op_name); \ + OP_MATHI_CASE_FLOAT(op_name); \ + default: \ + SET_INT_VALUE(regs[a+1], b); \ + c = 1; \ + mid = mrb_intern_lit(mrb, MRB_STRINGIZE(OP_MATH_OP_##op_name)); \ + goto L_SEND_SYM; \ + } \ + NEXT; +#define OP_MATHI_CASE_FIXNUM(op_name) \ + case MRB_TT_FIXNUM: \ + { \ + mrb_int x = mrb_fixnum(regs[a]), y = (mrb_int)b, z; \ + if (mrb_int_##op_name##_overflow(x, y, &z)) \ + OP_MATH_OVERFLOW_INT(op_name, x, y, z); \ + else \ + SET_INT_VALUE(regs[a], z); \ + } \ + break +#ifdef MRB_WITHOUT_FLOAT +#define OP_MATHI_CASE_FLOAT(op_name) (void)0 +#else +#define OP_MATHI_CASE_FLOAT(op_name) \ + case MRB_TT_FLOAT: \ + { \ + mrb_float z = mrb_float(regs[a]) OP_MATH_OP_##op_name b; \ + SET_FLOAT_VALUE(mrb, regs[a], z); \ + } \ + break #endif - default: - SET_INT_VALUE(regs[a+1], b); - c = 1; - mid = mrb_intern_lit(mrb, "+"); - goto L_SEND_SYM; - } - NEXT; + + CASE(OP_ADDI, BB) { + OP_MATHI(add); } CASE(OP_SUBI, BB) { - mrb_value *regs_a = regs + a; - - /* need to check if + is overridden */ - switch (mrb_type(regs_a[0])) { - case MRB_TT_FIXNUM: - { - mrb_int x = mrb_fixnum(regs_a[0]); - mrb_int y = (mrb_int)b; - mrb_int z; - - if (mrb_int_sub_overflow(x, y, &z)) { -#ifndef MRB_WITHOUT_FLOAT - SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y); - break; -#endif - } - SET_INT_VALUE(regs_a[0], z); - } - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float x = mrb_float(regs[a]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)b); - } - break; -#endif - default: - SET_INT_VALUE(regs_a[1], b); - c = 1; - mid = mrb_intern_lit(mrb, "-"); - goto L_SEND_SYM; - } - NEXT; + OP_MATHI(sub); } #define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1])) -- cgit v1.2.3 From 6b8d3c70702948e630536e7c42400e928ed9d773 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 15 Apr 2019 07:13:19 +0900 Subject: Fixed wrong function names; fix #4380 --- src/numeric.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 742df7b76..8205e41f6 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -510,7 +510,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) } static mrb_value -flo_lshift(mrb_state *mrb, mrb_value x) +flo_rshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -519,7 +519,7 @@ flo_lshift(mrb_state *mrb, mrb_value x) } static mrb_value -flo_rshift(mrb_state *mrb, mrb_value x) +flo_lshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -1608,8 +1608,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ -- cgit v1.2.3 From 4e45e320b05afb500a9acedc5b7a2c19b2b7158d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 16 Apr 2019 18:47:46 +0900 Subject: Fixed a bug in recursive `mrb_top_run` calls; fix #4384 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index a7ecc575d..9c07b8caa 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2863,11 +2863,11 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta return mrb_vm_run(mrb, proc, self, stack_keep); } ci = cipush(mrb); + ci->stackent = mrb->c->stack; ci->mid = 0; ci->acc = CI_ACC_SKIP; ci->target_class = mrb->object_class; v = mrb_vm_run(mrb, proc, self, stack_keep); - cipop(mrb); return v; } -- cgit v1.2.3 From 0e6a93a9ca9b207ce26073597e2abe26bbbb2c0d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 22 Apr 2019 19:09:29 +0900 Subject: Use `MRB_ASPEC_XXX()` macro in `codedump()` --- src/codedump.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/codedump.c b/src/codedump.c index 5bffefddb..12d609075 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -266,13 +266,13 @@ codedump(mrb_state *mrb, mrb_irep *irep) break; CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", - (a>>18)&0x1f, - (a>>13)&0x1f, - (a>>12)&0x1, - (a>>7)&0x1f, - (a>>2)&0x1f, - (a>>1)&0x1, - a & 0x1); + MRB_ASPEC_REQ(a), + MRB_ASPEC_OPT(a), + MRB_ASPEC_REST(a), + MRB_ASPEC_POST(a), + MRB_ASPEC_KEY(a), + MRB_ASPEC_KDICT(a), + MRB_ASPEC_BLOCK(a)); break; CASE(OP_KEY_P, BB): printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); -- cgit v1.2.3 From e9f3902ab5544de31fc91459e1846650aa228142 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 23 Apr 2019 15:30:10 +0900 Subject: Fixed the condition in `mrb_funcall_with_block`; fix #4389 --- src/vm.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 9c07b8caa..8dc6623d1 100644 --- a/src/vm.c +++ b/src/vm.c @@ -490,22 +490,21 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; } - if (MRB_METHOD_CFUNC_P(m)) { - mrb_stack_extend(mrb, argc + 2); - } - else if (argc >= CALL_MAXARGS) { + if (argc >= CALL_MAXARGS) { mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); - mrb_stack_extend(mrb, 3); mrb->c->stack[1] = args; ci->argc = -1; argc = 1; } - else if (MRB_METHOD_PROC_P(m)) { + mrb_stack_extend(mrb, argc + 2); + if (MRB_METHOD_PROC_P(m)) { struct RProc *p = MRB_METHOD_PROC(m); ci->proc = p; - mrb_stack_extend(mrb, p->body.irep->nregs + argc); + if (!MRB_PROC_CFUNC_P(p)) { + mrb_stack_extend(mrb, p->body.irep->nregs + argc); + } } if (voff >= 0) { argv = mrb->c->stbase + voff; -- cgit v1.2.3 From cc7f9190ba93ef45bf85a7278dffe6326cf620a3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 23 Apr 2019 20:45:38 +0900 Subject: Fix name assignment to frozen anonymous class/module Fix the following issues: A = Class.new.freeze #=> FrozenError Module.new::B = Class.new.freeze #=> FrozenError String::B = Module.new.freeze #=> FrozenError --- include/mruby/variable.h | 1 + src/class.c | 6 +++--- src/variable.c | 21 ++++++++++++--------- test/t/module.rb | 4 ++++ 4 files changed, 20 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/include/mruby/variable.h b/include/mruby/variable.h index ba6037959..ff01e5cc8 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -117,6 +117,7 @@ MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass * c, mrb_sym sym, mrb_ MRB_API void mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v); MRB_API mrb_bool mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym); mrb_value mrb_obj_iv_inspect(mrb_state*, struct RObject*); +void mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod); mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self); mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value); diff --git a/src/class.c b/src/class.c index d6efdbdc4..77ff04437 100644 --- a/src/class.c +++ b/src/class.c @@ -66,15 +66,15 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb name = mrb_class_path(mrb, outer); if (mrb_nil_p(name)) { /* unnamed outer class */ if (outer != mrb->object_class && outer != c) { - mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), - mrb_obj_value(outer)); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), + mrb_obj_value(outer)); } return; } mrb_str_cat_cstr(mrb, name, "::"); mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id)); } - mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); } static void diff --git a/src/variable.c b/src/variable.c index 983fe52f7..e859f02bf 100644 --- a/src/variable.c +++ b/src/variable.c @@ -341,21 +341,24 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); -MRB_API void -mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +void +mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t; - - mrb_check_frozen(mrb, obj); assign_class_name(mrb, obj, sym, v); if (!obj->iv) { obj->iv = iv_new(mrb); } - t = obj->iv; - iv_put(mrb, t, sym, v); + iv_put(mrb, obj->iv, sym, v); mrb_write_barrier(mrb, (struct RBasic*)obj); } +MRB_API void +mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + mrb_check_frozen(mrb, obj); + mrb_obj_iv_set_force(mrb, obj, sym, v); +} + /* Iterates over the instance variable table. */ MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) @@ -385,10 +388,10 @@ assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) if (mrb_nil_p(o)) { if ((struct RClass *)obj == mrb->object_class) { - mrb_obj_iv_set(mrb, c, id_classname, mrb_symbol_value(sym)); + mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym)); } else { - mrb_obj_iv_set(mrb, c, id_outer, mrb_obj_value(obj)); + mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj)); } } } diff --git a/test/t/module.rb b/test/t/module.rb index 09613e1bc..f4999019a 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -653,6 +653,10 @@ assert('Module#to_s') do assert_match "#", Module.new.to_s assert_match "#", Class.new.to_s + + assert_equal "FrozenClassToS", (FrozenClassToS = Class.new.freeze).to_s + assert_equal "Outer::A", (Outer::A = Module.new.freeze).to_s + assert_match "#::A", (Module.new::A = Class.new.freeze).to_s end assert('Module#inspect') do -- cgit v1.2.3 From 0c5f26e0ffc30bdc88b857daed1c9fe18c4b8f0c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 24 Apr 2019 09:43:12 +0900 Subject: Remove unnecessary `mrb_regexp_check()` and related functions. --- include/mruby.h | 4 ---- include/mruby/string.h | 3 --- include/mruby/value.h | 1 - src/etc.c | 16 ---------------- src/string.c | 39 ++++++--------------------------------- 5 files changed, 6 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index de6a803ef..dcd64b2d8 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -196,13 +196,9 @@ struct mrb_jmpbuf; typedef void (*mrb_atexit_func)(struct mrb_state*); -#define MRB_STATE_NO_REGEXP 1 -#define MRB_STATE_REGEXP 2 - typedef struct mrb_state { struct mrb_jmpbuf *jmp; - uint32_t flags; mrb_allocf allocf; /* memory allocation function */ void *allocf_ud; /* auxiliary data of allocf */ diff --git a/include/mruby/string.h b/include/mruby/string.h index 0b90debec..22445f654 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -433,9 +433,6 @@ mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str); */ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); -void mrb_noregexp(mrb_state *mrb, mrb_value self); -void mrb_regexp_check(mrb_state *mrb, mrb_value obj); - /* For backward compatibility */ #define mrb_str_cat2(mrb, str, ptr) mrb_str_cat_cstr(mrb, str, ptr) #define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) diff --git a/include/mruby/value.h b/include/mruby/value.h index 0446e772c..4d47d30ff 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -180,7 +180,6 @@ typedef void mrb_value; #define mrb_cptr_p(o) (mrb_type(o) == MRB_TT_CPTR) #define mrb_exception_p(o) (mrb_type(o) == MRB_TT_EXCEPTION) #define mrb_test(o) mrb_bool(o) -MRB_API mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value); /* * Returns a float in Ruby. diff --git a/src/etc.c b/src/etc.c index d15b398dd..ac1540f92 100644 --- a/src/etc.c +++ b/src/etc.c @@ -194,22 +194,6 @@ mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) } #endif /* MRB_WORD_BOXING */ -MRB_API mrb_bool -mrb_regexp_p(mrb_state *mrb, mrb_value v) -{ - if (mrb->flags & MRB_STATE_NO_REGEXP) { - return FALSE; - } - if ((mrb->flags & MRB_STATE_REGEXP) || mrb_class_defined(mrb, REGEXP_CLASS)) { - mrb->flags |= MRB_STATE_REGEXP; - return mrb_obj_is_kind_of(mrb, v, mrb_class_get(mrb, REGEXP_CLASS)); - } - else { - mrb->flags |= MRB_STATE_NO_REGEXP; - } - return FALSE; -} - #if defined _MSC_VER && _MSC_VER < 1900 #ifndef va_copy diff --git a/src/string.c b/src/string.c index f7a805a94..89ab59d4b 100644 --- a/src/string.c +++ b/src/string.c @@ -997,20 +997,6 @@ mrb_string_value_len(mrb_state *mrb, mrb_value ptr) return RSTRING_LEN(ptr); } -void -mrb_noregexp(mrb_state *mrb, mrb_value self) -{ - mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented"); -} - -void -mrb_regexp_check(mrb_state *mrb, mrb_value obj) -{ - if (mrb_regexp_p(mrb, obj)) { - mrb_noregexp(mrb, obj); - } -} - MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str) { @@ -1026,7 +1012,6 @@ mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) { mrb_int idx; - mrb_regexp_check(mrb, indx); switch (mrb_type(indx)) { case MRB_TT_FIXNUM: idx = mrb_fixnum(indx); @@ -1119,7 +1104,6 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) if (argc == 2) { mrb_int n1, n2; - mrb_regexp_check(mrb, a1); mrb_get_args(mrb, "ii", &n1, &n2); return str_substr(mrb, str, n1, n2); } @@ -1549,7 +1533,6 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - mrb_regexp_check(mrb, sub); clen = RSTRING_CHAR_LEN(str); if (pos < 0) { pos += clen; @@ -1801,7 +1784,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) if (pos < 0) { pos += len; if (pos < 0) { - mrb_regexp_check(mrb, sub); return mrb_nil_value(); } } @@ -1815,7 +1797,6 @@ mrb_str_rindex(mrb_state *mrb, mrb_value str) sub = mrb_nil_value(); } pos = chars2bytes(str, 0, pos); - mrb_regexp_check(mrb, sub); switch (mrb_type(sub)) { default: { @@ -1909,16 +1890,11 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) if (argc == 0 || mrb_nil_p(spat)) { split_type = awk; } - else { - if (mrb_string_p(spat)) { - split_type = string; - if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { - split_type = awk; - } - } - else { - mrb_noregexp(mrb, str); - } + else if (!mrb_string_p(spat)) { + mrb_raise(mrb, E_TYPE_ERROR, "expected String"); + } + else if (RSTRING_LEN(spat) == 1 && RSTRING_PTR(spat)[0] == ' ') { + split_type = awk; } result = mrb_ary_new(mrb); @@ -1955,7 +1931,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } } - else if (split_type == string) { + else { /* split_type == string */ mrb_int str_len = RSTRING_LEN(str); mrb_int pat_len = RSTRING_LEN(spat); mrb_int idx = 0; @@ -1976,9 +1952,6 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } beg = idx; } - else { - mrb_noregexp(mrb, str); - } if (RSTRING_LEN(str) > 0 && (lim_p || RSTRING_LEN(str) > beg || lim < 0)) { if (RSTRING_LEN(str) == beg) { tmp = mrb_str_new_empty(mrb, str); -- cgit v1.2.3 From 4720648137f2698cceb635c251475dec645cd598 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 24 Apr 2019 21:05:44 +0900 Subject: Fix modiying class variable to frozen class/module --- mrbgems/mruby-metaprog/test/metaprog.rb | 8 +++++++- src/variable.c | 2 ++ test/t/class.rb | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 1262c9945..0abeb90a6 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -171,7 +171,6 @@ assert('Module#class_variable_set', '15.2.2.4.18') do @@foo end end - assert_equal 99, Test4ClassVariableSet.class_variable_set(:@@cv, 99) assert_equal 101, Test4ClassVariableSet.class_variable_set(:@@foo, 101) assert_true Test4ClassVariableSet.class_variables.include? :@@cv @@ -180,6 +179,13 @@ assert('Module#class_variable_set', '15.2.2.4.18') do %w[@@ @@1 @@x= @x @ x 1].each do |n| assert_raise(NameError) { Test4ClassVariableSet.class_variable_set(n, 1) } end + + m = Module.new.freeze + assert_raise(FrozenError) { m.class_variable_set(:@@cv, 1) } + + parent = Class.new{ class_variable_set(:@@a, nil) }.freeze + child = Class.new(parent) + assert_raise(FrozenError) { child.class_variable_set(:@@a, 1) } end assert('Module#class_variables', '15.2.2.4.19') do diff --git a/src/variable.c b/src/variable.c index 983fe52f7..c4c9d369f 100644 --- a/src/variable.c +++ b/src/variable.c @@ -671,6 +671,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { + mrb_check_frozen(mrb, c); iv_put(mrb, t, sym, v); mrb_write_barrier(mrb, (struct RBasic*)c); return; @@ -698,6 +699,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) c = cls; } + mrb_check_frozen(mrb, c); if (!c->iv) { c->iv = iv_new(mrb); } diff --git a/test/t/class.rb b/test/t/class.rb index 290ecf74a..0c95677fc 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -433,6 +433,25 @@ assert('overriding class variable with a module (#3235)') do end end +assert('class variable for frozen class/module') do + module CVarForFrozenModule + freeze + assert_raise(FrozenError) { @@cv = 1 } + end + + class CVarForFrozenClassA + @@a = nil + freeze + end + class CVarForFrozenClassB < CVarForFrozenClassA + def a=(v) + @@a = v + end + end + b = CVarForFrozenClassB.new + assert_raise(FrozenError) { b.a = 1 } +end + assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } -- cgit v1.2.3 From 4d85019e4cc3748a75d7c542fba80fcbf8554d5c Mon Sep 17 00:00:00 2001 From: dearblue Date: Wed, 24 Apr 2019 22:14:12 +0900 Subject: Check mruby binary version --- src/load.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/load.c b/src/load.c index ab0346750..01c97b926 100644 --- a/src/load.c +++ b/src/load.c @@ -539,6 +539,10 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t return MRB_DUMP_INVALID_FILE_HEADER; } + if (memcmp(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version)) != 0) { + return MRB_DUMP_INVALID_FILE_HEADER; + } + if (crc) { *crc = bin_to_uint16(header->binary_crc); } -- cgit v1.2.3 From 58d525c9fafcc78af25d22f984821eda19d0913c Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 6 Apr 2019 14:25:26 +0900 Subject: Check mruby binary size --- src/load.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/load.c b/src/load.c index 01c97b926..cc011fba7 100644 --- a/src/load.c +++ b/src/load.c @@ -519,10 +519,14 @@ lv_exit: } static int -read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t *flags) +read_binary_header(const uint8_t *bin, size_t bufsize, size_t *bin_size, uint16_t *crc, uint8_t *flags) { const struct rite_binary_header *header = (const struct rite_binary_header *)bin; + if (bufsize < sizeof(struct rite_binary_header)) { + return MRB_DUMP_READ_FAULT; + } + if (memcmp(header->binary_ident, RITE_BINARY_IDENT, sizeof(header->binary_ident)) == 0) { if (bigendian_p()) *flags |= FLAG_BYTEORDER_NATIVE; @@ -548,11 +552,15 @@ read_binary_header(const uint8_t *bin, size_t *bin_size, uint16_t *crc, uint8_t } *bin_size = (size_t)bin_to_uint32(header->binary_size); + if (bufsize < *bin_size) { + return MRB_DUMP_READ_FAULT; + } + return MRB_DUMP_OK; } static mrb_irep* -read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) +read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags) { int result; mrb_irep *irep = NULL; @@ -565,7 +573,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return NULL; } - result = read_binary_header(bin, &bin_size, &crc, &flags); + result = read_binary_header(bin, bufsize, &bin_size, &crc, &flags); if (result != MRB_DUMP_OK) { return NULL; } @@ -618,7 +626,7 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) uint8_t flags = FLAG_SRC_STATIC; #endif - return read_irep(mrb, bin, flags); + return read_irep(mrb, bin, (size_t)-1, flags); } void mrb_exc_set(mrb_state *mrb, mrb_value exc); @@ -680,7 +688,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf, header_size, 1, fp) == 0) { goto irep_exit; } - result = read_binary_header(buf, &buf_size, NULL, &flags); + result = read_binary_header(buf, (size_t)-1, &buf_size, NULL, &flags); if (result != MRB_DUMP_OK || buf_size <= header_size) { goto irep_exit; } @@ -689,7 +697,7 @@ mrb_read_irep_file(mrb_state *mrb, FILE* fp) if (fread(buf+header_size, buf_size-header_size, 1, fp) == 0) { goto irep_exit; } - irep = read_irep(mrb, buf, FLAG_SRC_MALLOC); + irep = read_irep(mrb, buf, (size_t)-1, FLAG_SRC_MALLOC); irep_exit: mrb_free(mrb, buf); -- cgit v1.2.3 From 8f6f36f6540408d3b1b5a0dddf440d53b43e53e4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 6 Apr 2019 14:37:25 +0900 Subject: Add mruby binary loader functions from buffer memory Add new functions (with `MRB_API`): - `mrb_read_irep_buf()` - `mrb_load_irep_buf()` - `mrb_load_irep_buf_cxt()` --- include/mruby/dump.h | 1 + include/mruby/irep.h | 12 ++++++++++++ src/load.c | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+) (limited to 'src') diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 0234a362b..201d7ef61 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -31,6 +31,7 @@ MRB_API mrb_value mrb_load_irep_file(mrb_state*,FILE*); MRB_API mrb_value mrb_load_irep_file_cxt(mrb_state*, FILE*, mrbc_context*); #endif MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); +MRB_API mrb_irep *mrb_read_irep_buf(mrb_state*, const void*, size_t); /* dump/load error code * diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 027a294d5..d42fd0fb8 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -52,9 +52,21 @@ MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb); /* @param [const uint8_t*] irep code, expected as a literal */ MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*); +/* + * @param [const void*] irep code + * @param [size_t] size of irep buffer. If -1 is given, it is considered unrestricted. + */ +MRB_API mrb_value mrb_load_irep_buf(mrb_state*, const void*, size_t); + /* @param [const uint8_t*] irep code, expected as a literal */ MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*); +/* + * @param [const void*] irep code + * @param [size_t] size of irep buffer. If -1 is given, it is considered unrestricted. + */ +MRB_API mrb_value mrb_load_irep_buf_cxt(mrb_state*, const void*, size_t, mrbc_context*); + void mrb_irep_free(mrb_state*, struct mrb_irep*); void mrb_irep_incref(mrb_state*, struct mrb_irep*); void mrb_irep_decref(mrb_state*, struct mrb_irep*); diff --git a/src/load.c b/src/load.c index cc011fba7..0274f30d4 100644 --- a/src/load.c +++ b/src/load.c @@ -629,6 +629,12 @@ mrb_read_irep(mrb_state *mrb, const uint8_t *bin) return read_irep(mrb, bin, (size_t)-1, flags); } +MRB_API mrb_irep* +mrb_read_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return read_irep(mrb, (const uint8_t *)buf, bufsize, FLAG_SRC_MALLOC); +} + void mrb_exc_set(mrb_state *mrb, mrb_value exc); static void @@ -662,12 +668,24 @@ mrb_load_irep_cxt(mrb_state *mrb, const uint8_t *bin, mrbc_context *c) return load_irep(mrb, mrb_read_irep(mrb, bin), c); } +MRB_API mrb_value +mrb_load_irep_buf_cxt(mrb_state *mrb, const void *buf, size_t bufsize, mrbc_context *c) +{ + return load_irep(mrb, mrb_read_irep_buf(mrb, buf, bufsize), c); +} + MRB_API mrb_value mrb_load_irep(mrb_state *mrb, const uint8_t *bin) { return mrb_load_irep_cxt(mrb, bin, NULL); } +MRB_API mrb_value +mrb_load_irep_buf(mrb_state *mrb, const void *buf, size_t bufsize) +{ + return mrb_load_irep_buf_cxt(mrb, buf, bufsize, NULL); +} + #ifndef MRB_DISABLE_STDIO mrb_irep* -- cgit v1.2.3 From 8fa3995a1a02e9014ce01351e0260bec20ceefd7 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 25 Apr 2019 19:48:40 +0900 Subject: Singleton class of frozen object should be frozen Before this patch: p (class << Object.new.freeze; self end).frozen? #=> false sc = class << (o=Object.new); self end; o.freeze; p sc.frozen? #=> false After this patch / Ruby: p (class << Object.new.freeze; self end).frozen? #=> true sc = class << (o=Object.new); self end; o.freeze; p sc.frozen? #=> true --- mrbgems/mruby-metaprog/test/metaprog.rb | 16 ++++++++++++++++ src/class.c | 1 + src/kernel.c | 1 + test/t/class.rb | 7 +++++++ 4 files changed, 25 insertions(+) (limited to 'src') diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 0abeb90a6..3aa1d8732 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -122,6 +122,22 @@ assert('Kernel#define_singleton_method') do assert_equal :singleton_method_ok, o.test_method end +assert('Kernel#singleton_class') do + o1 = Object.new + assert_same(o1.singleton_class, class << o1; self end) + + o2 = Object.new + sc2 = class << o2; self end + assert_same(o2.singleton_class, sc2) + + o3 = Object.new + sc3 = o3.singleton_class + o3.freeze + assert_predicate(sc3, :frozen?) + + assert_predicate(Object.new.freeze.singleton_class, :frozen?) +end + def labeled_module(name, &block) Module.new do (class <flags |= o->flags & MRB_FL_OBJ_IS_FROZEN; } static mrb_value diff --git a/src/kernel.c b/src/kernel.c index d9a1d36ce..45bca7558 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -438,6 +438,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) struct RBasic *b = mrb_basic_ptr(self); if (!MRB_FROZEN_P(b)) { MRB_SET_FROZEN_FLAG(b); + if (b->c->tt == MRB_TT_SCLASS) MRB_SET_FROZEN_FLAG(b->c); } } return self; diff --git a/test/t/class.rb b/test/t/class.rb index 0c95677fc..e2839111c 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -356,6 +356,13 @@ assert('singleton tests') do end end end if Object.const_defined?(:Float) + + o = Object.new + sc = class << o; self end + o.freeze + assert_predicate(sc, :frozen?) + + assert_predicate(class << Object.new.freeze; self end, :frozen?) end assert('clone Class') do -- cgit v1.2.3 From 1a8f6e70b5e91dcbdf92a3b671e00cd7410c3cc1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 1 May 2019 15:04:08 +0900 Subject: Remove unneeded `argc` check in `mrb_str_aref_m()` --- src/string.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 89ab59d4b..90e609992 100644 --- a/src/string.c +++ b/src/string.c @@ -1107,9 +1107,6 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) mrb_get_args(mrb, "ii", &n1, &n2); return str_substr(mrb, str, n1, n2); } - if (argc != 1) { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc)); - } return mrb_str_aref(mrb, str, a1); } -- cgit v1.2.3 From 95a92d35c89ec9c39c97c5f948255389a129029e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 2 May 2019 20:45:31 +0900 Subject: Unify overflow error class for conversion to integer to `RangeError` --- src/numeric.c | 2 +- src/string.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 8205e41f6..101b338de 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1230,7 +1230,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) z = (mrb_int)d; } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x); + mrb_raisef(mrb, E_RANGE_ERROR, "number (%S) too big for integer", x); } } return mrb_fixnum_value(z); diff --git a/src/string.c b/src/string.c index 89ab59d4b..955ad57ce 100644 --- a/src/string.c +++ b/src/string.c @@ -2115,7 +2115,7 @@ mrb_str_len_to_inum(mrb_state *mrb, const char *str, mrb_int len, mrb_int base, else #endif { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "string (%S) too big for integer", + mrb_raisef(mrb, E_RANGE_ERROR, "string (%S) too big for integer", mrb_str_new(mrb, str, pend-str)); } } -- cgit v1.2.3 From e86e360b360029a432af42dbb414b7df21eb0c2b Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 3 May 2019 11:42:14 +0900 Subject: Fix `FLAG_SRC_STATIC` always set in `mrb_read_irep()` with `MRB_USE_CUSTOM_RO_DATA_P` --- src/load.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/load.c b/src/load.c index ab0346750..70f18da31 100644 --- a/src/load.c +++ b/src/load.c @@ -608,7 +608,7 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) mrb_irep* mrb_read_irep(mrb_state *mrb, const uint8_t *bin) { -#ifdef MRB_USE_ETEXT_EDATA +#if defined(MRB_USE_ETEXT_EDATA) || defined(MRB_USE_CUSTOM_RO_DATA_P) uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC; #else uint8_t flags = FLAG_SRC_STATIC; -- cgit v1.2.3 From 0692f7916cc9865e276a58812186cac7f02dc042 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 3 May 2019 13:39:19 +0900 Subject: Simplify conversion process for `i` in `mrb_get_args()` --- src/class.c | 24 +----------------------- test/t/string.rb | 11 +++++++---- 2 files changed, 8 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 254f5b005..2cabc820e 100644 --- a/src/class.c +++ b/src/class.c @@ -838,29 +838,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_int*); if (i < argc) { - switch (mrb_type(ARGV[arg_i])) { - case MRB_TT_FIXNUM: - *p = mrb_fixnum(ARGV[arg_i]); - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float f = mrb_float(ARGV[arg_i]); - - if (!FIXABLE_FLOAT(f)) { - mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); - } - *p = (mrb_int)f; - } - break; -#endif - case MRB_TT_STRING: - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer"); - break; - default: - *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); - break; - } + *p = mrb_fixnum(mrb_to_int(mrb, ARGV[arg_i])); arg_i++; i++; } diff --git a/test/t/string.rb b/test/t/string.rb index e563db55a..e5b001366 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -37,11 +37,14 @@ end assert('String#*', '15.2.10.5.5') do assert_equal 'aaaaa', 'a' * 5 assert_equal '', 'a' * 0 - assert_raise(ArgumentError) do - 'a' * -1 - end + assert_equal 'aa', 'a' * 2.1 + assert_raise(ArgumentError) { 'a' * -1 } + assert_raise(RangeError) { '' * 1e30 } + assert_raise(RangeError) { '' * Float::INFINITY } + assert_raise(RangeError) { '' * Float::NAN } + assert_raise(TypeError) { 'a' * '1' } + assert_raise(TypeError) { 'a' * nil } end - assert('String#[]', '15.2.10.5.6') do # length of args is 1 a = 'abc'[0] -- cgit v1.2.3 From a5bda13fb76ba50c3742b24b854fb2e86c50b31d Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 4 May 2019 16:38:07 +0900 Subject: Check whether object is immediate in `mrb_gc_(register|unregister)` --- src/gc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 27f3716ec..5e7440d50 100644 --- a/src/gc.c +++ b/src/gc.c @@ -466,9 +466,12 @@ mrb_gc_protect(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_register(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table) || mrb_type(table) != MRB_TT_ARRAY) { table = mrb_ary_new(mrb); mrb_gv_set(mrb, root, table); @@ -480,11 +483,14 @@ mrb_gc_register(mrb_state *mrb, mrb_value obj) MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj) { - mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); - mrb_value table = mrb_gv_get(mrb, root); + mrb_sym root; + mrb_value table; struct RArray *a; mrb_int i; + if (mrb_immediate_p(obj)) return; + root = mrb_intern_lit(mrb, GC_ROOT_NAME); + table = mrb_gv_get(mrb, root); if (mrb_nil_p(table)) return; if (mrb_type(table) != MRB_TT_ARRAY) { mrb_gv_set(mrb, root, mrb_nil_value()); -- cgit v1.2.3 From 35943e7beb0e4fd22f2096b56817e0cf22b8cf42 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 7 May 2019 23:01:13 +0900 Subject: Refactor `mrb_str_to_cstr` and `mrb_string_value_cstr` - Extract null byte check to function. - Avoid string allocation if null byte is included. - Use `str_new` instead of `mrb_str_dup` + `mrb_str_modify` --- mrbgems/mruby-io/test/file.rb | 3 +++ src/string.c | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 88ced31a6..1535ebb44 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -33,6 +33,7 @@ assert('File.basename') do assert_equal 'a', File.basename('/a/') assert_equal 'b', File.basename('/a/b') assert_equal 'b', File.basename('../a/b') + assert_raise(ArgumentError) { File.basename("/a/b\0") } end assert('File.dirname') do @@ -106,6 +107,8 @@ assert('File.realpath') do MRubyIOTestUtil.rmdir dir end end + + assert_raise(ArgumentError) { File.realpath("TO\0DO") } end assert("File.readlink") do diff --git a/src/string.c b/src/string.c index f043bfd5a..7fc405a2b 100644 --- a/src/string.c +++ b/src/string.c @@ -194,6 +194,15 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } +static void +check_null_byte(mrb_state *mrb, mrb_value str) +{ + mrb_to_str(mrb, str); + if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + } +} + void mrb_gc_free_str(mrb_state *mrb, struct RString *str) { @@ -723,14 +732,8 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { struct RString *s; - if (!mrb_string_p(str0)) { - mrb_raise(mrb, E_TYPE_ERROR, "expected String"); - } - + check_null_byte(mrb, str0); s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); - if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); - } return RSTR_PTR(s); } @@ -2144,20 +2147,27 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badchec MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - mrb_value str = mrb_to_str(mrb, *ptr); - struct RString *ps = mrb_str_ptr(str); - mrb_int len = mrb_str_strlen(mrb, ps); - char *p = RSTR_PTR(ps); + struct RString *ps; + const char *p; + mrb_int len; - if (!p || p[len] != '\0') { + check_null_byte(mrb, *ptr); + ps = mrb_str_ptr(*ptr); + p = RSTR_PTR(ps); + len = RSTR_LEN(ps); + if (p[len] == '\0') { + return p; + } + else { if (MRB_FROZEN_P(ps)) { - *ptr = str = mrb_str_dup(mrb, str); - ps = mrb_str_ptr(str); + ps = str_new(mrb, p, len); + *ptr = mrb_obj_value(ps); + } + else { + mrb_str_modify(mrb, ps); } - mrb_str_modify(mrb, ps); return RSTR_PTR(ps); } - return p; } MRB_API mrb_value -- cgit v1.2.3 From 1975dedb214b9d181630c337374702a1b4725288 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 8 May 2019 20:35:03 +0900 Subject: Use `mrb_string_value_cstr` in `mrb_str_to_dbl` --- mrbgems/mruby-kernel-ext/test/kernel.rb | 2 ++ src/string.c | 17 +---------------- 2 files changed, 3 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-kernel-ext/test/kernel.rb b/mrbgems/mruby-kernel-ext/test/kernel.rb index 28f089007..ad9177165 100644 --- a/mrbgems/mruby-kernel-ext/test/kernel.rb +++ b/mrbgems/mruby-kernel-ext/test/kernel.rb @@ -65,6 +65,8 @@ assert('Kernel#Float') do assert_equal(123.456, Float(123.456)) assert_equal(123.456, Float("123.456")) assert_raise(TypeError) { Float(nil) } + assert_raise(ArgumentError) { Float("1.5a") } + assert_raise(ArgumentError) { Float("1.5\0") } end assert('Kernel#String') do diff --git a/src/string.c b/src/string.c index 7fc405a2b..578e3bdcc 100644 --- a/src/string.c +++ b/src/string.c @@ -2281,22 +2281,7 @@ bad: MRB_API double mrb_str_to_dbl(mrb_state *mrb, mrb_value str, mrb_bool badcheck) { - char *s; - mrb_int len; - - mrb_to_str(mrb, str); - s = RSTRING_PTR(str); - len = RSTRING_LEN(str); - if (s) { - if (badcheck && memchr(s, '\0', len)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string for Float contains null byte"); - } - if (s[len]) { /* no sentinel somehow */ - struct RString *temp_str = str_new(mrb, s, len); - s = RSTR_PTR(temp_str); - } - } - return mrb_cstr_to_dbl(mrb, s, badcheck); + return mrb_cstr_to_dbl(mrb, mrb_string_value_cstr(mrb, &str), badcheck); } /* 15.2.10.5.39 */ -- cgit v1.2.3 From fa317fabbd400204dfb11171155c30feb92a2293 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 11 May 2019 18:40:33 +0900 Subject: Use `mrb_ensure_string_type` in `mrb_to_str` --- src/object.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/object.c b/src/object.c index d45ab27c7..7c1879019 100644 --- a/src/object.c +++ b/src/object.c @@ -584,11 +584,7 @@ mrb_Float(mrb_state *mrb, mrb_value val) MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val) { - if (!mrb_string_p(val)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to String", type); - } - return val; + return mrb_ensure_string_type(mrb, val); } /* obsolete: use mrb_ensure_string_type() instead */ -- cgit v1.2.3 From 752edf413f09fb3e78d79ca7d752ae5dc2e25c02 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 16 May 2019 09:51:27 +0900 Subject: Terminate float right shift if shift value is too big. --- src/numeric.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 101b338de..5dbf9df22 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -484,6 +484,10 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) if (width < 0) { while (width++) { val /= 2; + if (val < 1.0) { + val = 0; + break; + } } #if defined(_ISOC99_SOURCE) val = trunc(val); -- cgit v1.2.3 From 80c789b3941160312ac7ffed202abe8c23bc0628 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:40:19 +0900 Subject: Use `int64_t` instead of `mrb_int` in `int64_value`. --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 5dbf9df22..113413502 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -421,7 +421,7 @@ value_int64(mrb_state *mrb, mrb_value x) static mrb_value int64_value(mrb_state *mrb, int64_t v) { - if (FIXABLE(v)) { + if (TYPED_FIXABLE(v,int64_t)) { return mrb_fixnum_value((mrb_int)v); } return mrb_float_value(mrb, (mrb_float)v); -- cgit v1.2.3 From 8a9f984eb8771a3d4956783116f972d4f5f70dfd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:42:16 +0900 Subject: Add a new function `mrb_int_value`. This function returns `Fixnum` if the value fits in `mrb_int`, otherwise it returns `Float` value (mruby behavior of handling integers). --- src/numeric.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 113413502..30b6b230e 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -44,6 +44,15 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) } return mrb_float(val); } + +static mrb_value +mrb_int_value(mrb_state *mrb, mrb_float f) +{ + if (FIXABLE_FLOAT(f)) { + return mrb_fixnum_value((mrb_int)f); + } + return mrb_float_value(mrb, f); +} #endif /* @@ -507,10 +516,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) val *= 2; } } - if (FIXABLE_FLOAT(val)) { - return mrb_fixnum_value((mrb_int)val); - } - return mrb_float_value(mrb, val); + return mrb_int_value(mrb, val); } static mrb_value @@ -616,10 +622,7 @@ flo_floor(mrb_state *mrb, mrb_value num) mrb_float f = floor(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.8 */ @@ -642,10 +645,7 @@ flo_ceil(mrb_state *mrb, mrb_value num) mrb_float f = ceil(mrb_float(num)); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } /* 15.2.9.3.12 */ @@ -748,10 +748,7 @@ flo_truncate(mrb_state *mrb, mrb_value num) if (f < 0.0) f = ceil(f); mrb_check_num_exact(mrb, f); - if (!FIXABLE_FLOAT(f)) { - return mrb_float_value(mrb, f); - } - return mrb_fixnum_value((mrb_int)f); + return mrb_int_value(mrb, f); } static mrb_value -- cgit v1.2.3 From bc18060149fae9121fe744544521ca58989010ae Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 10:44:56 +0900 Subject: Change the `num.divmod(float)` to return `[int,num]`. --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 30b6b230e..ab8771e1a 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -934,7 +934,7 @@ fix_divmod(mrb_state *mrb, mrb_value x) mrb_value a, b; flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } @@ -952,7 +952,7 @@ flo_divmod(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod); - a = mrb_float_value(mrb, div); + a = mrb_int_value(mrb, div); b = mrb_float_value(mrb, mod); return mrb_assoc_new(mrb, a, b); } -- cgit v1.2.3 From 3734c53eb8e5fd34f572b62e2f85ed43b4f6d921 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:13:12 +0900 Subject: Make `flo_rount` to return `Integeral`. --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index ab8771e1a..954e91019 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -726,7 +726,7 @@ flo_round(mrb_state *mrb, mrb_value num) if (!isfinite(number)) return num; return mrb_float_value(mrb, number); } - return mrb_fixnum_value((mrb_int)number); + return mrb_int_value(mrb, number); } /* 15.2.9.3.14 */ -- cgit v1.2.3 From 223defd62ae511786a2b50c68ed97b73bfc05d59 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:26:16 +0900 Subject: Move `Numeric#div` to the core. --- mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb | 4 ---- src/numeric.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb index f250538fe..e86e8b283 100644 --- a/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb +++ b/mrbgems/mruby-numeric-ext/mrblib/numeric_ext.rb @@ -1,8 +1,4 @@ module Integral - def div(other) - self.divmod(other)[0] - end - def zero? self == 0 end diff --git a/src/numeric.c b/src/numeric.c index 954e91019..8c17635a2 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -136,6 +136,25 @@ mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +static mrb_value +num_idiv(mrb_state *mrb, mrb_value x) +{ +#ifdef MRB_WITHOUT_FLOAT + mrb_value y; + + mrb_get_args(mrb, "o", &y); + if (!mrb_fixnum_p(y)) { + mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + } + return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); +#else + mrb_float y; + + mrb_get_args(mrb, "f", &y); + return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y); +#endif +} + /* 15.2.9.3.19(x) */ /* * call-seq: @@ -1552,6 +1571,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, numeric, "div", num_idiv, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 0c91da257bf64769d85a709852cfa2da313a4185 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:27:21 +0900 Subject: Remove unused `mrb_num_div()` function. --- include/mruby/numeric.h | 1 - src/numeric.c | 35 +++++++++++------------------------ 2 files changed, 11 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 9a04631d6..2fae3142d 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -39,7 +39,6 @@ MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y); mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y); #ifndef __has_builtin #define __has_builtin(x) 0 diff --git a/src/numeric.c b/src/numeric.c index 8c17635a2..8e5fefa04 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -112,30 +112,6 @@ num_pow(mrb_state *mrb, mrb_value x) #endif } -/* 15.2.8.3.4 */ -/* 15.2.9.3.4 */ -/* - * call-seq: - * num / other -> num - * - * Performs division: the class of the resulting object depends on - * the class of num and on the magnitude of the - * result. - */ - -mrb_value -mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y) -{ -#ifdef MRB_WITHOUT_FLOAT - if (!mrb_fixnum_p(y)) { - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); - } - return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y)); -#else - return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y)); -#endif -} - static mrb_value num_idiv(mrb_state *mrb, mrb_value x) { @@ -155,6 +131,17 @@ num_idiv(mrb_state *mrb, mrb_value x) #endif } +/* 15.2.8.3.4 */ +/* 15.2.9.3.4 */ +/* + * call-seq: + * num / other -> num + * + * Performs division: the class of the resulting object depends on + * the class of num and on the magnitude of the + * result. + */ + /* 15.2.9.3.19(x) */ /* * call-seq: -- cgit v1.2.3 From 237a57bbe831c57d3ebb0f9cc69768dbc8dda589 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 17 May 2019 11:30:38 +0900 Subject: Make unused functions private. * mrb_fixnum_plus() * mrb_fixnum_minus() * mrb_fixnum_mul() --- include/mruby/numeric.h | 4 ---- src/numeric.c | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 2fae3142d..9d87ca5c4 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -36,10 +36,6 @@ MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt) MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); #endif -mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y); -mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y); - #ifndef __has_builtin #define __has_builtin(x) 0 #endif diff --git a/src/numeric.c b/src/numeric.c index 8e5fefa04..6622a46e9 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -787,7 +787,7 @@ int_to_i(mrb_state *mrb, mrb_value num) return num; } -mrb_value +static mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1244,7 +1244,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) } #endif -mrb_value +static mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1287,7 +1287,7 @@ fix_plus(mrb_state *mrb, mrb_value self) return mrb_fixnum_plus(mrb, self, other); } -mrb_value +static mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; -- cgit v1.2.3 From e41f15747eea34ea45e0258f0755145fcd10293b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:10:20 +0900 Subject: Rename `struct RIstruct` to `struct RIStruct`. --- include/mruby/istruct.h | 4 ++-- src/gc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/include/mruby/istruct.h b/include/mruby/istruct.h index 4d2393ccd..23c9bfa36 100644 --- a/include/mruby/istruct.h +++ b/include/mruby/istruct.h @@ -19,12 +19,12 @@ MRB_BEGIN_DECL #define ISTRUCT_DATA_SIZE (sizeof(void*) * 3) -struct RIstruct { +struct RIStruct { MRB_OBJECT_HEADER; char inline_data[ISTRUCT_DATA_SIZE]; }; -#define RISTRUCT(obj) ((struct RIstruct*)(mrb_ptr(obj))) +#define RISTRUCT(obj) ((struct RIStruct*)(mrb_ptr(obj))) #define ISTRUCT_PTR(obj) (RISTRUCT(obj)->inline_data) MRB_INLINE mrb_int mrb_istruct_size() diff --git a/src/gc.c b/src/gc.c index 5e7440d50..6dc8e373b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -110,7 +110,7 @@ typedef struct { struct RHash hash; struct RRange range; struct RData data; - struct RIstruct istruct; + struct RIStruct istruct; struct RProc proc; struct REnv env; struct RFiber fiber; -- cgit v1.2.3 From 89d29264158946a62af8874b4f04e553b0528630 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 18 May 2019 11:48:59 +0900 Subject: Add ISO section number to `Module#===`. --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 9d26851b9..4cc60ab67 100644 --- a/src/class.c +++ b/src/class.c @@ -2191,7 +2191,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); -- cgit v1.2.3 From 4f71e9eebe2a4dc17092768aeabf75af0bbae1ce Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 18:22:56 +0900 Subject: Move `Numeric#__coerce_step_counter` to `Integral` This method is only used in `Integral#step` --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 6622a46e9..e73bdaca2 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -170,7 +170,7 @@ num_div(mrb_state *mrb, mrb_value x) } static mrb_value -num_coerce_step_counter(mrb_state *mrb, mrb_value self) +integral_coerce_step_counter(mrb_state *mrb, mrb_value self) { mrb_value counter = self, num, step; @@ -1551,6 +1551,7 @@ mrb_init_numeric(mrb_state *mrb) #endif integral = mrb_define_module(mrb, "Integral"); + mrb_define_method(mrb, integral, "__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ @@ -1566,7 +1567,6 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); - mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2)); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ -- cgit v1.2.3 From 6fb5979d29217386425044b8170acb7a9363ce0c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 18 May 2019 20:57:54 +0900 Subject: Move `Kernel#equal? to `BasicObject` --- src/class.c | 1 + src/kernel.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 4cc60ab67..6ceaa0cfa 100644 --- a/src/class.c +++ b/src/class.c @@ -2154,6 +2154,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */ + mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); diff --git a/src/kernel.c b/src/kernel.c index 45bca7558..349e71cb8 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -780,7 +780,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ mrb_define_method(mrb, krn, "dup", mrb_obj_dup, MRB_ARGS_NONE()); /* 15.3.1.3.9 */ mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ - mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); -- cgit v1.2.3 From 67fc3428cb6c0fae2c08c5de36adc7bd0990c4c0 Mon Sep 17 00:00:00 2001 From: dearblue Date: Mon, 6 May 2019 16:28:27 +0900 Subject: Remove "LINE" section reader Because it is not currently output by `mrbc`. --- include/mruby/dump.h | 5 ---- src/load.c | 67 ---------------------------------------------------- 2 files changed, 72 deletions(-) (limited to 'src') diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 0234a362b..4c7d08253 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -60,7 +60,6 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); #define RITE_BINARY_EOF "END\0" #define RITE_SECTION_IREP_IDENT "IREP" -#define RITE_SECTION_LINENO_IDENT "LINE" #define RITE_SECTION_DEBUG_IDENT "DBG\0" #define RITE_SECTION_LV_IDENT "LVAR" @@ -92,10 +91,6 @@ struct rite_section_irep_header { uint8_t rite_version[4]; /* Rite Instruction Specification Version */ }; -struct rite_section_lineno_header { - RITE_SECTION_HEADER; -}; - struct rite_section_debug_header { RITE_SECTION_HEADER; }; diff --git a/src/load.c b/src/load.c index 70f18da31..9af752a15 100644 --- a/src/load.c +++ b/src/load.c @@ -233,66 +233,6 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) return read_irep_record(mrb, bin, &len, flags); } -/* ignore lineno record */ -static int -read_lineno_record_1(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *len) -{ - size_t i, fname_len, niseq; - - *len = 0; - bin += sizeof(uint32_t); /* record size */ - *len += sizeof(uint32_t); - fname_len = bin_to_uint16(bin); - bin += sizeof(uint16_t); - *len += sizeof(uint16_t); - bin += fname_len; - *len += fname_len; - - niseq = (size_t)bin_to_uint32(bin); - bin += sizeof(uint32_t); /* niseq */ - *len += sizeof(uint32_t); - - if (SIZE_ERROR_MUL(niseq, sizeof(uint16_t))) { - return MRB_DUMP_GENERAL_FAILURE; - } - for (i = 0; i < niseq; i++) { - bin += sizeof(uint16_t); /* niseq */ - *len += sizeof(uint16_t); - } - - return MRB_DUMP_OK; -} - -static int -read_lineno_record(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep, size_t *lenp) -{ - int result = read_lineno_record_1(mrb, bin, irep, lenp); - int i; - - if (result != MRB_DUMP_OK) return result; - for (i = 0; i < irep->rlen; i++) { - size_t len; - - result = read_lineno_record(mrb, bin, irep->reps[i], &len); - if (result != MRB_DUMP_OK) break; - bin += len; - *lenp += len; - } - return result; -} - -static int -read_section_lineno(mrb_state *mrb, const uint8_t *bin, mrb_irep *irep) -{ - size_t len; - - len = 0; - bin += sizeof(struct rite_section_lineno_header); - - /* Read Binary Data Section */ - return read_lineno_record(mrb, bin, irep, &len); -} - static int read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len) { @@ -578,13 +518,6 @@ read_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags) irep = read_section_irep(mrb, bin, flags); if (!irep) return NULL; } - else if (memcmp(section_header->section_ident, RITE_SECTION_LINENO_IDENT, sizeof(section_header->section_ident)) == 0) { - if (!irep) return NULL; /* corrupted data */ - result = read_section_lineno(mrb, bin, irep); - if (result < MRB_DUMP_OK) { - return NULL; - } - } else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) { if (!irep) return NULL; /* corrupted data */ result = read_section_debug(mrb, bin, irep, flags); -- cgit v1.2.3 From 8b8bf9f3f696f28836138b8106147d9d3e6071a2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 14:59:25 +0900 Subject: Add new functions for numerical operation; ref 237a57b New functions: * mrb_num_plus(mrb, x, y) * mrb_num_minus(mrb, x, y) * num_num_mul(mrb, x, y) --- include/mruby/numeric.h | 4 ++++ src/numeric.c | 54 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 9d87ca5c4..d670504c2 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -36,6 +36,10 @@ MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt) MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); #endif +MRB_API mrb_value mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y); +MRB_API mrb_value mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y); +MRB_API mrb_value mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y); + #ifndef __has_builtin #define __has_builtin(x) 0 #endif diff --git a/src/numeric.c b/src/numeric.c index e73bdaca2..3ad5721ef 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -788,7 +788,7 @@ int_to_i(mrb_state *mrb, mrb_value num) } static mrb_value -mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -812,6 +812,20 @@ mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_mul(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); +} + /* 15.2.8.3.3 */ /* * call-seq: @@ -828,7 +842,7 @@ fix_mul(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - return mrb_fixnum_mul(mrb, x, y); + return fixnum_mul(mrb, x, y); } static void @@ -1245,7 +1259,7 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) #endif static mrb_value -mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1269,6 +1283,20 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_plus(mrb, x, y); + } +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); +} + /* 15.2.8.3.1 */ /* * call-seq: @@ -1284,11 +1312,11 @@ fix_plus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_plus(mrb, self, other); + return fixnum_plus(mrb, self, other); } static mrb_value -mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) +fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) { mrb_int a; @@ -1311,6 +1339,20 @@ mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) #endif } +MRB_API mrb_value +mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) +{ + if (mrb_fixnum_p(x)) { + return fixnum_minus(mrb, x, y); + } +#ifdef MRB_WITHOUT_FLOAT + if (mrb_float_p(x)) { + return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); + } +#endif + mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); +} + /* 15.2.8.3.2 */ /* 15.2.8.3.16 */ /* @@ -1327,7 +1369,7 @@ fix_minus(mrb_state *mrb, mrb_value self) mrb_value other; mrb_get_args(mrb, "o", &other); - return mrb_fixnum_minus(mrb, self, other); + return fixnum_minus(mrb, self, other); } -- cgit v1.2.3 From 3b46831da83b4d5d5355c60261fb3ebe2a885513 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 21 May 2019 20:26:53 +0900 Subject: Move `**`,`/`,`quo`,`div` and comparison methods to Integral from Numeric Having these methods in Numeric can get in the way of creating subclasses of Numeric because they only support Fixnum and Float. --- mrbgems/mruby-rational/mrblib/rational.rb | 3 --- src/numeric.c | 37 +++++++++++++++---------------- 2 files changed, 18 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb index 28c96c69f..cecede48a 100644 --- a/mrbgems/mruby-rational/mrblib/rational.rb +++ b/mrbgems/mruby-rational/mrblib/rational.rb @@ -1,7 +1,4 @@ class Rational < Numeric - # Override #<, #<=, #>, #>= in Numeric - prepend Comparable - def inspect "(#{to_s})" end diff --git a/src/numeric.c b/src/numeric.c index 3ad5721ef..c740a32e3 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -65,7 +65,7 @@ mrb_int_value(mrb_state *mrb, mrb_float f) * 2.0**3 #=> 8.0 */ static mrb_value -num_pow(mrb_state *mrb, mrb_value x) +integral_pow(mrb_state *mrb, mrb_value x) { mrb_value y; #ifndef MRB_WITHOUT_FLOAT @@ -113,7 +113,7 @@ num_pow(mrb_state *mrb, mrb_value x) } static mrb_value -num_idiv(mrb_state *mrb, mrb_value x) +integral_idiv(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -151,7 +151,7 @@ num_idiv(mrb_state *mrb, mrb_value x) */ static mrb_value -num_div(mrb_state *mrb, mrb_value x) +integral_div(mrb_state *mrb, mrb_value x) { #ifdef MRB_WITHOUT_FLOAT mrb_value y; @@ -1479,7 +1479,7 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) * basis for the tests in Comparable. */ static mrb_value -num_cmp(mrb_state *mrb, mrb_value self) +integral_cmp(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1499,7 +1499,7 @@ cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2) } static mrb_value -num_lt(mrb_state *mrb, mrb_value self) +integral_lt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1512,7 +1512,7 @@ num_lt(mrb_state *mrb, mrb_value self) } static mrb_value -num_le(mrb_state *mrb, mrb_value self) +integral_le(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1525,7 +1525,7 @@ num_le(mrb_state *mrb, mrb_value self) } static mrb_value -num_gt(mrb_state *mrb, mrb_value self) +integral_gt(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1538,7 +1538,7 @@ num_gt(mrb_state *mrb, mrb_value self) } static mrb_value -num_ge(mrb_state *mrb, mrb_value self) +integral_ge(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_int n; @@ -1593,20 +1593,19 @@ mrb_init_numeric(mrb_state *mrb) #endif integral = mrb_define_module(mrb, "Integral"); - mrb_define_method(mrb, integral, "__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ + mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2)); /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ - - mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ - mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ - mrb_define_method(mrb, numeric, "div", num_idiv, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ - mrb_define_method(mrb, numeric, "<", num_lt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, "<=", num_le, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">", num_gt, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); -- cgit v1.2.3 From 5d30309e9826fe1a392fa7a7a33e11ad58857b3f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 20 May 2019 16:32:00 +0900 Subject: Silence the return value warnings from gcc; ref 237a57b --- src/numeric.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index c740a32e3..140cd0101 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -824,6 +824,7 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.3 */ @@ -1295,6 +1296,7 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.1 */ @@ -1351,6 +1353,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) } #endif mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); + return mrb_nil_value(); /* not reached */ } /* 15.2.8.3.2 */ -- cgit v1.2.3 From e941cf06a3e0351107d36d49d540562fdf49f9b4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 16:08:02 +0900 Subject: Export `mrb_int_value` that converts `mrb_float` to `Fixnum`. Or `Float` if `mrb_float` value is too big (or too small) to fit in `mrb_int`. The `_int_` in `mrb_int_value` means `Integral` module, which represents integer-like values in mruby. --- include/mruby/numeric.h | 1 + src/numeric.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index d670504c2..34707e441 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -34,6 +34,7 @@ MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base); #ifndef MRB_WITHOUT_FLOAT MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt); MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); +MRB_API mrb_value mrb_int_value(mrb_state *mrb, mrb_float f); #endif MRB_API mrb_value mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y); diff --git a/src/numeric.c b/src/numeric.c index 140cd0101..e15b7f671 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -45,7 +45,7 @@ mrb_to_flo(mrb_state *mrb, mrb_value val) return mrb_float(val); } -static mrb_value +MRB_API mrb_value mrb_int_value(mrb_state *mrb, mrb_float f) { if (FIXABLE_FLOAT(f)) { -- cgit v1.2.3 From 38f8edbdd7463ee5e3331d09b2d031d55f2fd05e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 21 May 2019 21:12:33 +0900 Subject: Update ISO section number for some Numeric methods. --- src/numeric.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index e15b7f671..608b4f289 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1597,10 +1597,10 @@ mrb_init_numeric(mrb_state *mrb) integral = mrb_define_module(mrb, "Integral"); mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */ + mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6 */ mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */ + mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1 */ mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1)); -- cgit v1.2.3 From 56e0e1934d4ec751d83f9f54ce93ca74b0e21194 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 12:12:21 +0900 Subject: Name the return value of `mrb_range_beg_len()` --- include/mruby/range.h | 8 +++++++- mrbgems/mruby-array-ext/src/array.c | 2 +- mrbgems/mruby-kernel-ext/src/kernel.c | 2 +- mrbgems/mruby-string-ext/src/string.c | 6 +++--- src/array.c | 8 ++++---- src/range.c | 12 ++++++------ src/string.c | 4 ++-- 7 files changed, 24 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/include/mruby/range.h b/include/mruby/range.h index b5626993a..ee6eb8d1d 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -64,7 +64,13 @@ MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value range); */ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, mrb_bool exclude); -MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); +enum mrb_range_beg_len { + MRB_RANGE_TYPE_MISMATCH = 0, /* (failure) not range */ + MRB_RANGE_OK = 1, /* (success) range */ + MRB_RANGE_OUT = 2 /* (failure) out of range */ +}; + +MRB_API enum mrb_range_beg_len mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); void mrb_gc_mark_range(mrb_state *mrb, struct RRange *r); diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index b6d9c9c80..20c771a97 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -145,7 +145,7 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self) mrb_get_args(mrb, "o|i", &index, &len); switch (mrb_type(index)) { case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) { goto delete_pos_len; } else { diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 9288b0e6f..8e7e03c56 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -22,7 +22,7 @@ mrb_f_caller(mrb_state *mrb, mrb_value self) case 1: if (mrb_type(v) == MRB_TT_RANGE) { mrb_int beg, len; - if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == 1) { + if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == MRB_RANGE_OK) { lev = beg; n = len; } diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index ba7e3c610..85180516c 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -58,11 +58,11 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str) len = RSTRING_LEN(str); switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) { - case 0: /* not range */ + case MRB_RANGE_TYPE_MISMATCH: break; - case 1: /* range */ + case MRB_RANGE_OK: return mrb_str_substr(mrb, str, beg, len); - case 2: /* out of range */ + case MRB_RANGE_OUT: mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1); break; } diff --git a/src/array.c b/src/array.c index d4302cb22..bd9b4d358 100644 --- a/src/array.c +++ b/src/array.c @@ -858,7 +858,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self) switch (mrb_type(index)) { /* a[n..m] */ case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) { + if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == MRB_RANGE_OK) { return ary_subseq(mrb, a, i, len); } else { @@ -927,13 +927,13 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { /* a[n..m] = v */ switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) { - case 0: /* not range */ + case MRB_RANGE_TYPE_MISMATCH: mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); break; - case 1: /* range */ + case MRB_RANGE_OK: mrb_ary_splice(mrb, self, i, len, v2); break; - case 2: /* out of range */ + case MRB_RANGE_OUT: mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); break; } diff --git a/src/range.c b/src/range.c index 21771c8ec..9036ef093 100644 --- a/src/range.c +++ b/src/range.c @@ -352,7 +352,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con if (mrb_fixnum_p(argv[i])) { mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i]))); } - else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) { + else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == MRB_RANGE_OK) { mrb_int const end = olen < beg + len ? olen : beg + len; for (j = beg; j < end; ++j) { mrb_ary_push(mrb, result, func(mrb, obj, j)); @@ -398,13 +398,13 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) return mrb_range_value(r); } -MRB_API mrb_int +MRB_API enum mrb_range_beg_len mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; struct RRange *r; - if (mrb_type(range) != MRB_TT_RANGE) return 0; + if (mrb_type(range) != MRB_TT_RANGE) return MRB_RANGE_TYPE_MISMATCH; r = mrb_range_ptr(mrb, range); beg = mrb_int(mrb, RANGE_BEG(r)); @@ -412,11 +412,11 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, if (beg < 0) { beg += len; - if (beg < 0) return 2; + if (beg < 0) return MRB_RANGE_OUT; } if (trunc) { - if (beg > len) return 2; + if (beg > len) return MRB_RANGE_OUT; if (end > len) end = len; } @@ -427,7 +427,7 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, *begp = beg; *lenp = len; - return 1; + return MRB_RANGE_OK; } void diff --git a/src/string.c b/src/string.c index 578e3bdcc..db2d73e32 100644 --- a/src/string.c +++ b/src/string.c @@ -1041,9 +1041,9 @@ num_index: len = RSTRING_CHAR_LEN(str); switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { - case 1: + case MRB_RANGE_OK: return str_subseq(mrb, str, beg, len); - case 2: + case MRB_RANGE_OUT: return mrb_nil_value(); default: break; -- cgit v1.2.3 From ecfca8def78043f891bcbe6bc1eb036048996169 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 22:24:08 +0900 Subject: Fix double rounded by negative index - Before patched: ``` $ mruby -e 'p (-12..-1).map { |i| "Hello"[i] }.join' "HelloHello" ``` - After patched: ``` $ mruby -e 'p (-12..-1).map { |i| "Hello"[i] }.join' "Hello" ``` --- src/string.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index db2d73e32..bfe73b359 100644 --- a/src/string.c +++ b/src/string.c @@ -449,9 +449,6 @@ str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) if (clen == 0) { len = 0; } - else if (beg < 0) { - beg = clen + beg; - } if (beg > clen) return mrb_nil_value(); if (beg < 0) { beg += clen; -- cgit v1.2.3 From d1e1bb0d5b45d9f1c5de943a036c86542698af49 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 25 May 2019 23:59:43 +0900 Subject: Remove `mrb_alloca()` function When I found this function, I expected it to behave the same as the `alloca(3)` function, but it is accually the `mrb_alloca()` function does not free the heap until the `mrb_close()` function is called. Also, even if it is deleted, it can be replaced with the combination of the `MRB_TT_DATA` object and the `mrb_gv_set()` function if it is sure necessary. --- include/mruby.h | 2 -- src/state.c | 33 --------------------------------- 2 files changed, 35 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 20cdc1b83..5d5c759dd 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -228,7 +228,6 @@ typedef struct mrb_state { struct RClass *symbol_class; struct RClass *kernel_module; - struct alloca_header *mems; mrb_gc gc; #ifdef MRB_METHOD_CACHE @@ -1247,7 +1246,6 @@ MRB_API void mrb_pool_close(struct mrb_pool*); MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t); MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); -MRB_API void* mrb_alloca(mrb_state *mrb, size_t); MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); diff --git a/src/state.c b/src/state.c index 08d7ba906..c42df71ba 100644 --- a/src/state.c +++ b/src/state.c @@ -57,38 +57,6 @@ mrb_default_allocf(mrb_state *mrb, void *p, size_t size, void *ud) } } -struct alloca_header { - struct alloca_header *next; - char buf[1]; -}; - -MRB_API void* -mrb_alloca(mrb_state *mrb, size_t size) -{ - struct alloca_header *p; - - p = (struct alloca_header*) mrb_malloc(mrb, sizeof(struct alloca_header)+size); - p->next = mrb->mems; - mrb->mems = p; - return (void*)p->buf; -} - -static void -mrb_alloca_free(mrb_state *mrb) -{ - struct alloca_header *p; - struct alloca_header *tmp; - - if (mrb == NULL) return; - p = mrb->mems; - - while (p) { - tmp = p; - p = p->next; - mrb_free(mrb, tmp); - } -} - MRB_API mrb_state* mrb_open(void) { @@ -256,7 +224,6 @@ mrb_close(mrb_state *mrb) mrb_gc_free_gv(mrb); mrb_free_context(mrb, mrb->root_c); mrb_free_symtbl(mrb); - mrb_alloca_free(mrb); mrb_gc_destroy(mrb, &mrb->gc); mrb_free(mrb, mrb); } -- cgit v1.2.3 From 779251de64bdf63f71b02927db511fb8633c5d60 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 26 May 2019 20:32:04 +0900 Subject: Move `mrb_mod_s_nesting()` to `mruby-metaprog` gem from the core --- mrbgems/mruby-metaprog/src/metaprog.c | 26 ++++++++++++++++++++++++-- src/vm.c | 25 ------------------------- 2 files changed, 24 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 0aafb4c34..38f75d460 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -657,8 +657,30 @@ mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); /* not reached */ } -/* implementation of Module.nesting */ -mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); +mrb_value +mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) +{ + struct RProc *proc; + mrb_value ary; + struct RClass *c = NULL; + + mrb_get_args(mrb, ""); + ary = mrb_ary_new(mrb); + proc = mrb->c->ci[-1].proc; /* callee proc */ + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + while (proc) { + if (MRB_PROC_SCOPE_P(proc)) { + struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); + + if (c2 != c) { + c = c2; + mrb_ary_push(mrb, ary, mrb_obj_value(c)); + } + } + proc = proc->upper; + } + return ary; +} void mrb_mruby_metaprog_gem_init(mrb_state* mrb) diff --git a/src/vm.c b/src/vm.c index 8dc6623d1..0a6d4af8d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -830,31 +830,6 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const return mrb_exec_irep(mrb, self, p); } -mrb_value -mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) -{ - struct RProc *proc; - mrb_value ary; - struct RClass *c = NULL; - - mrb_get_args(mrb, ""); - ary = mrb_ary_new(mrb); - proc = mrb->c->ci[-1].proc; /* callee proc */ - mrb_assert(!MRB_PROC_CFUNC_P(proc)); - while (proc) { - if (MRB_PROC_SCOPE_P(proc)) { - struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); - - if (c2 != c) { - c = c2; - mrb_ary_push(mrb, ary, mrb_obj_value(c)); - } - } - proc = proc->upper; - } - return ary; -} - static struct RBreak* break_new(mrb_state *mrb, struct RProc *p, mrb_value val) { -- cgit v1.2.3 From 2b81ea7ec1c7645b13b097e5b249cbc99f374da7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 28 May 2019 10:44:18 +0900 Subject: Add `mrb_alloca` again; ref #4470 This time, the allocated memory comes from the string object, which is referenced from GC arena. The memory region will be reclaimed when the C function called from VM is terminated, or the GC arena is restored. --- include/mruby.h | 2 ++ src/gc.c | 7 +++++++ 2 files changed, 9 insertions(+) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 5d5c759dd..3ef399716 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1246,6 +1246,8 @@ MRB_API void mrb_pool_close(struct mrb_pool*); MRB_API void* mrb_pool_alloc(struct mrb_pool*, size_t); MRB_API void* mrb_pool_realloc(struct mrb_pool*, void*, size_t oldlen, size_t newlen); MRB_API mrb_bool mrb_pool_can_realloc(struct mrb_pool*, void*, size_t); +/* temporary memory allocation, only effective while GC arena is kept */ +MRB_API void* mrb_alloca(mrb_state *mrb, size_t); MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func); diff --git a/src/gc.c b/src/gc.c index 6dc8e373b..94068c0f9 100644 --- a/src/gc.c +++ b/src/gc.c @@ -277,6 +277,13 @@ mrb_free(mrb_state *mrb, void *p) (mrb->allocf)(mrb, p, 0, mrb->allocf_ud); } +MRB_API void* +mrb_alloca(mrb_state *mrb, size_t size) +{ + mrb_value str = mrb_str_new(mrb, NULL, size); + return RSTRING_PTR(str); +} + static mrb_bool heap_p(mrb_gc *gc, struct RBasic *object) { -- cgit v1.2.3 From 729931a06c0eebb8c1eaa471f2a1d16192deca9f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 May 2019 12:33:41 +0900 Subject: Fix inverted compilation condition; fix #4478 --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 608b4f289..0d1c23589 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1347,7 +1347,7 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) if (mrb_fixnum_p(x)) { return fixnum_minus(mrb, x, y); } -#ifdef MRB_WITHOUT_FLOAT +#ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(x)) { return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); } -- cgit v1.2.3 From 4b83fe8b04f61e62d851648c0fe95e8e575181d5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 7 Jun 2019 22:02:43 +0900 Subject: Remove `Kernel#global_variables` from core This method is defined in `mruby-metaprog` gem. --- mrbgems/mruby-metaprog/src/metaprog.c | 2 +- mrbgems/mruby-metaprog/test/metaprog.rb | 12 ++++++++++++ src/kernel.c | 1 - test/t/kernel.rb | 15 --------------- 4 files changed, 13 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index e57d10d8d..43d27f4dc 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -686,7 +686,7 @@ mrb_mruby_metaprog_gem_init(mrb_state* mrb) struct RClass *krn = mrb->kernel_module; struct RClass *mod = mrb->module_class; - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ + mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 (15.3.1.2.4) */ mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 3aa1d8732..329580abc 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -99,6 +99,18 @@ assert('Kernel#singleton_methods', '15.3.1.3.45') do assert_equal singleton_methods.class, Array end +assert('Kernel.global_variables', '15.3.1.2.4') do + assert_equal Array, Kernel.global_variables.class +end + +assert('Kernel#global_variables', '15.3.1.3.14') do + variables = global_variables + assert_equal Array, variables.class + 1.upto(9) do |i| + assert_equal variables.include?(:"$#{i}"), true + end +end + assert('Kernel.local_variables', '15.3.1.2.7') do a, b = 0, 1 a += b diff --git a/src/kernel.c b/src/kernel.c index 349e71cb8..a3c2d2ec6 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -783,7 +783,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); - mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ diff --git a/test/t/kernel.rb b/test/t/kernel.rb index bf7dbe94c..7f6e6c58d 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -31,10 +31,6 @@ end # Kernel.eval is provided by the mruby-gem mrbgem. '15.3.1.2.3' -assert('Kernel.global_variables', '15.3.1.2.4') do - assert_equal Array, Kernel.global_variables.class -end - assert('Kernel.iterator?', '15.3.1.2.5') do assert_false Kernel.iterator? end @@ -266,10 +262,6 @@ assert('Kernel#frozen?') do assert_true 0.0.frozen? end -assert('Kernel#global_variables', '15.3.1.3.14') do - assert_equal Array, global_variables.class -end - assert('Kernel#hash', '15.3.1.3.15') do assert_equal hash, hash end @@ -488,13 +480,6 @@ assert('Kernel#respond_to_missing?') do assert_false Test4RespondToMissing.new.respond_to?(:no_method) end -assert('Kernel#global_variables') do - variables = global_variables - 1.upto(9) do |i| - assert_equal variables.include?(:"$#{i}"), true - end -end - assert('stack extend') do def recurse(count, stop) return count if count > stop -- cgit v1.2.3 From 38f1da6f26bde5185612b66a1b1fc94f78654d78 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 10 Jun 2019 18:46:57 +0900 Subject: `Kernel#global_variables` should not include undefined `$1`-`$9` - They are not include in Ruby. - Appear in duplicate when `$1`-`$9` are defined. --- mrbgems/mruby-metaprog/test/metaprog.rb | 13 ++++++++----- src/variable.c | 8 -------- 2 files changed, 8 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 329580abc..685fdf196 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -104,11 +104,14 @@ assert('Kernel.global_variables', '15.3.1.2.4') do end assert('Kernel#global_variables', '15.3.1.3.14') do - variables = global_variables - assert_equal Array, variables.class - 1.upto(9) do |i| - assert_equal variables.include?(:"$#{i}"), true - end + variables1 = global_variables + assert_equal Array, variables1.class + assert_not_include(variables1, :$kernel_global_variables_test) + + $kernel_global_variables_test = nil + variables2 = global_variables + assert_include(variables2, :$kernel_global_variables_test) + assert_equal(1, variables2.size - variables1.size) end assert('Kernel.local_variables', '15.3.1.2.7') do diff --git a/src/variable.c b/src/variable.c index ee21a3b96..779f206dc 100644 --- a/src/variable.c +++ b/src/variable.c @@ -965,16 +965,8 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) { iv_tbl *t = mrb->globals; mrb_value ary = mrb_ary_new(mrb); - size_t i; - char buf[3]; iv_foreach(mrb, t, gv_i, &ary); - buf[0] = '$'; - buf[2] = 0; - for (i = 1; i <= 9; ++i) { - buf[1] = (char)(i + '0'); - mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2))); - } return ary; } -- cgit v1.2.3 From 9bd692bc67ee302bcbc359d0841458339c440fb4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 13 Jun 2019 21:24:48 +0900 Subject: Fix class name validation in `Struct.new` Before this patch: $ bin/mruby -e 'p Struct.new("A-")' #=> Struct::"A-" After this patch: $ bin/mruby -e 'p Struct.new("A-")' #=> NameError: identifier A- needs to be constant --- include/mruby/class.h | 1 + mrbgems/mruby-struct/src/struct.c | 2 +- mrbgems/mruby-struct/test/struct.rb | 4 ++++ src/class.c | 14 +++++++------- 4 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/include/mruby/class.h b/include/mruby/class.h index a68724538..c79a487b5 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -88,6 +88,7 @@ MRB_API struct RClass* mrb_class_real(struct RClass* cl); mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv); void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym); +mrb_bool mrb_const_name_p(mrb_state*, const char*, mrb_int); mrb_value mrb_class_find_path(mrb_state*, struct RClass*); void mrb_gc_mark_mt(mrb_state*, struct RClass*); size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*); diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 1df135a9f..539127bf8 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -212,7 +212,7 @@ make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass *kl /* old style: should we warn? */ mrb_to_str(mrb, name); id = mrb_obj_to_sym(mrb, name); - if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) { + if (!mrb_const_name_p(mrb, RSTRING_PTR(name), RSTRING_LEN(name))) { mrb_name_error(mrb, id, "identifier %S needs to be constant", name); } if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) { diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index 91e8cecc6..9f2ff1cdc 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -181,6 +181,10 @@ assert("Struct.new does not allow array") do end end +assert("Struct.new does not allow invalid class name") do + assert_raise(NameError) { Struct.new("Test-", :a) } +end + assert("Struct.new generates subclass of Struct") do begin original_struct = Struct diff --git a/src/class.c b/src/class.c index 6ceaa0cfa..373f2aec7 100644 --- a/src/class.c +++ b/src/class.c @@ -77,6 +77,12 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); } +mrb_bool +mrb_const_name_p(mrb_state *mrb, const char *name, mrb_int len) +{ + return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); +} + static void setup_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb_sym id) { @@ -1852,18 +1858,12 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static mrb_bool -const_name_p(mrb_state *mrb, const char *name, mrb_int len) -{ - return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); -} - static void check_const_name_sym(mrb_state *mrb, mrb_sym id) { mrb_int len; const char *name = mrb_sym2name_len(mrb, id, &len); - if (!const_name_p(mrb, name, len)) { + if (!mrb_const_name_p(mrb, name, len)) { mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); } } -- cgit v1.2.3 From 030dd6655e47dad4af4b48a74646712c00684698 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 16 Jun 2019 20:43:23 +0900 Subject: Fix cvar, ivar, const and method can be removed to frozen object --- mrbgems/mruby-metaprog/src/metaprog.c | 1 + mrbgems/mruby-metaprog/test/metaprog.rb | 8 ++++++-- src/variable.c | 1 + test/t/kernel.rb | 1 + test/t/module.rb | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c index 43d27f4dc..0d207ef41 100644 --- a/mrbgems/mruby-metaprog/src/metaprog.c +++ b/mrbgems/mruby-metaprog/src/metaprog.c @@ -641,6 +641,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) mrb_value *argv; mrb_get_args(mrb, "*", &argv, &argc); + mrb_check_frozen(mrb, mrb_obj_ptr(mod)); while (argc--) { remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv)); argv++; diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index 685fdf196..46b98d0ed 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -298,6 +298,9 @@ assert('Module#remove_class_variable', '15.2.2.4.39') do assert_raise(NameError) do Test4RemoveClassVariable.remove_class_variable(:@v) end + assert_raise(FrozenError) do + Test4RemoveClassVariable.freeze.remove_class_variable(:@@cv) + end end assert('Module#remove_method', '15.2.2.4.41') do @@ -305,9 +308,9 @@ assert('Module#remove_method', '15.2.2.4.41') do class Parent def hello end - end + end - class Child < Parent + class Child < Parent def hello end end @@ -317,6 +320,7 @@ assert('Module#remove_method', '15.2.2.4.41') do assert_same klass, klass.class_eval{ remove_method :hello } assert_true klass.instance_methods.include? :hello assert_false klass.instance_methods(false).include? :hello + assert_raise(FrozenError) { klass.freeze.remove_method :m } end assert('Module.nesting', '15.2.2.2.2') do diff --git a/src/variable.c b/src/variable.c index 779f206dc..23d900b7d 100644 --- a/src/variable.c +++ b/src/variable.c @@ -521,6 +521,7 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) { + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (obj_iv_p(obj)) { iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 7f6e6c58d..950442351 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -404,6 +404,7 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do assert_equal nil, tri.var assert_raise(NameError) { tri.remove } assert_raise(NameError) { tri.remove_instance_variable(:var) } + assert_raise(FrozenError) { tri.freeze.remove } end # Kernel#require is defined in mruby-require. '15.3.1.3.42' diff --git a/test/t/module.rb b/test/t/module.rb index 3bb9735df..571f4759d 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -262,6 +262,7 @@ assert('Module#remove_const', '15.2.2.4.40') do %i[x X!].each do |n| assert_raise(NameError) { Test4RemoveConst.remove_const(n) } end + assert_raise(FrozenError) { Test4RemoveConst.freeze.remove_const(:A) } end assert('Module#const_missing', '15.2.2.4.22') do -- cgit v1.2.3 From 758353902940e43530dbbbab0d9ce6ded5884923 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:48:22 +0900 Subject: Fix potential overflow in `utf8len()` For example on 32 bit mode, when `p = 0xfffffffd`, `e = 0xfffffffe` and `len = 4`, the sum of `p` and `len` can be to `1`, and comparison with `e` will to be false. As a result, a segmentation fault occurs by referring to address 0. --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index bfe73b359..ed58c484b 100644 --- a/src/string.c +++ b/src/string.c @@ -234,7 +234,7 @@ utf8len(const char* p, const char* e) mrb_int i; len = utf8len_codepage[(unsigned char)*p]; - if (p + len > e) return 1; + if (len > e - p) return 1; for (i = 1; i < len; ++i) if ((p[i] & 0xc0) != 0x80) return 1; -- cgit v1.2.3 From 28de6b0da195e1ebf8f6ce30de462f44fb761b8b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 22 Jun 2019 19:05:42 +0900 Subject: Refine `Hash#rehash` example [ci skip] Previous example doesn't work because string key (frozen) can't be modified. --- src/hash.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index a9367a426..b4d96251c 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1378,10 +1378,21 @@ mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2) * values of key objects have changed since they were inserted, this * method will reindex hsh. * - * h = {"AAA" => "b"} - * h.keys[0].chop! - * h.rehash #=> {"AA"=>"b"} - * h["AA"] #=> "b" + * keys = (1..17).map{|n| [n]} + * k = keys[0] + * h = {} + * keys.each{|key| h[key] = key[0]} + * h #=> { [1]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> 1 + * k[0] = keys.size + 1 + * h #=> {[18]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7, + * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14, + * [15]=>15,[16]=>16,[17]=>17} + * h[k] #=> nil + * h.rehash + * h[k] #=> 1 */ static mrb_value mrb_hash_rehash(mrb_state *mrb, mrb_value self) -- cgit v1.2.3 From 7c6d6effaea6ec3cbac01cffc4f094744d53d8b9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:30:36 +0900 Subject: Replacement to function for string reversing --- src/string.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index bfe73b359..282f8d776 100644 --- a/src/string.c +++ b/src/string.c @@ -1671,6 +1671,18 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } +static inline void +str_reverse(char *p, char *e) +{ + char c; + + while (p < e) { + c = *p; + *p++ = *e; + *e-- = c; + } +} + /* 15.2.10.5.30 */ /* * call-seq: @@ -1714,17 +1726,12 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); char *p, *e; - char c; mrb_str_modify(mrb, s); if (RSTR_LEN(s) > 1) { p = RSTR_PTR(s); e = p + RSTR_LEN(s) - 1; - while (p < e) { - c = *p; - *p++ = *e; - *e-- = c; - } + str_reverse(p, e); } return str; } -- cgit v1.2.3 From bd2c93c2dfbb944f57b10b7b9c056caf852a5053 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 16:32:17 +0900 Subject: Change to UTF-8 string reversing with in place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverses UTF-8 strings without allocated heap for working memory. 1. String before reversing: ``` "!yburmの界世" # byte unit [33, 121, 98, 117, 114, 109, 227, 129, 174, 231, 149, 140, 228, 184, 150] ``` 2. Reverse the byte order of each character: ``` [33, 121, 98, 117, 114, 109, 174, 129, 227, 140, 149, 231, 150, 184, 228] ``` 3. Reverse the whole byte order and complete: ``` [228, 184, 150, 231, 149, 140, 227, 129, 174, 109, 114, 117, 98, 121, 33] # string "世界のmruby!" ``` --- src/string.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 282f8d776..6d01b773c 100644 --- a/src/string.c +++ b/src/string.c @@ -1693,40 +1693,28 @@ str_reverse(char *p, char *e) static mrb_value mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) { + struct RString *s = mrb_str_ptr(str); + char *p, *e; + #ifdef MRB_UTF8_STRING mrb_int utf8_len = RSTRING_CHAR_LEN(str); - mrb_int len = RSTRING_LEN(str); + mrb_int len = RSTR_LEN(s); if (utf8_len == len) goto bytes; if (utf8_len > 1) { - char *buf; - char *p, *e, *r; - - mrb_str_modify(mrb, mrb_str_ptr(str)); - len = RSTRING_LEN(str); - buf = (char*)mrb_malloc(mrb, (size_t)len); - p = buf; - e = buf + len; - - memcpy(buf, RSTRING_PTR(str), len); - r = RSTRING_PTR(str) + len; - + mrb_str_modify(mrb, s); + p = RSTR_PTR(s); + e = p + RSTR_LEN(s); while (p 1) { p = RSTR_PTR(s); -- cgit v1.2.3 From 567075aab939dd262e816832195cb11594abade9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 22:58:18 +0900 Subject: Fix string brakes for one UTF-8 charactor --- src/string.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 6d01b773c..a35262eb4 100644 --- a/src/string.c +++ b/src/string.c @@ -1700,8 +1700,8 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) mrb_int utf8_len = RSTRING_CHAR_LEN(str); mrb_int len = RSTR_LEN(s); - if (utf8_len == len) goto bytes; - if (utf8_len > 1) { + if (utf8_len < 2) return str; + if (utf8_len < len) { mrb_str_modify(mrb, s); p = RSTR_PTR(s); e = p + RSTR_LEN(s); @@ -1711,8 +1711,6 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) p += clen; } } - - bytes: #endif { mrb_str_modify(mrb, s); -- cgit v1.2.3 From ec03e3f54af55af8c461a19b2f7cf0a984282997 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 23:02:29 +0900 Subject: Delete the unnecessary block brace in `mrb_str_reverse_bang` --- src/string.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index a35262eb4..2cfdc337e 100644 --- a/src/string.c +++ b/src/string.c @@ -1712,15 +1712,14 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) } } #endif - { - mrb_str_modify(mrb, s); - if (RSTR_LEN(s) > 1) { - p = RSTR_PTR(s); - e = p + RSTR_LEN(s) - 1; - str_reverse(p, e); - } - return str; + + mrb_str_modify(mrb, s); + if (RSTR_LEN(s) > 1) { + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + str_reverse(p, e); } + return str; } /* ---------------------------------- */ -- cgit v1.2.3 From 11e09dc5dbd6ddaabf145bbee62741f4191eca79 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 22 Jun 2019 23:09:36 +0900 Subject: Fix the unnecessary `mrb_str_modify()` call Now to be calls `mrb_str_modify()` only once when 2 or more characters. --- src/string.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 2cfdc337e..2d9d176d4 100644 --- a/src/string.c +++ b/src/string.c @@ -1710,11 +1710,13 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) str_reverse(p, p + clen - 1); p += clen; } + goto bytes; } #endif - mrb_str_modify(mrb, s); if (RSTR_LEN(s) > 1) { + mrb_str_modify(mrb, s); + bytes: p = RSTR_PTR(s); e = p + RSTR_LEN(s) - 1; str_reverse(p, e); -- cgit v1.2.3 From 1fd08aee15942c3b3e3133f8cc92d4025df024a8 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 23 Jun 2019 20:01:33 +0900 Subject: Fix argument specs to `Array` --- mrbgems/mruby-array-ext/src/array.c | 2 +- src/array.c | 58 ++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index 20c771a97..cb4798d49 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -194,7 +194,7 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY()); - mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ANY()); + mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ARG(1,1)); } void diff --git a/src/array.c b/src/array.c index bd9b4d358..8cf813743 100644 --- a/src/array.c +++ b/src/array.c @@ -1262,39 +1262,39 @@ mrb_init_array(mrb_state *mrb) { struct RClass *a; - mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ + mrb->array_class = a = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY); - mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ - - mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ - mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ - mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ - mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ - mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ - mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ - mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ - mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ - mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ - mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ - mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ - mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ - mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */ - mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */ - mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ - mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ - mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ - mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ - mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ - mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ - mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ - mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ - mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ - mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ - mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ + mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ + + mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ + mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ + mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ + mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.4 */ + mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ARG(2,1)); /* 15.2.12.5.5 */ + mrb_define_method(mrb, a, "clear", mrb_ary_clear_m, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ + mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ + mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ + mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ + mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ + mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ + mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ + mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_OPT(1)); /* 15.2.12.5.17 */ + mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_OPT(1)); /* 15.2.12.5.18 */ + mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ + mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ + mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ + mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ + mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ + mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ + mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ + mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ + mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ + mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ARG(1,1)); /* 15.2.12.5.29 */ + mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ + mrb_define_method(mrb, a, "__ary_index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* kept for mruby-array-ext */ mrb_define_method(mrb, a, "__svalue", mrb_ary_svalue, MRB_ARGS_NONE()); } -- cgit v1.2.3 From f71270df7736e9cd53845c45d1eb369227c853ea Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 24 Jun 2019 18:55:05 +0900 Subject: Compare obj pointer directly instead of using mrb_obj_eq in mrb_gc_unregister Because immediate values are not registered. --- src/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 94068c0f9..b05d929a1 100644 --- a/src/gc.c +++ b/src/gc.c @@ -506,7 +506,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) a = mrb_ary_ptr(table); mrb_ary_modify(mrb, a); for (i = 0; i < ARY_LEN(a); i++) { - if (mrb_obj_eq(mrb, ARY_PTR(a)[i], obj)) { + if (mrb_ptr(ARY_PTR(a)[i]) == mrb_ptr(obj)) { mrb_int len = ARY_LEN(a)-1; mrb_value *ptr = ARY_PTR(a); -- cgit v1.2.3 From dc21024ec795bcfcd3018825fa3c272731439a7e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:05:33 +0900 Subject: Fix `mrb_str_to_str()` to handle symbols. --- src/string.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index ed58c484b..856e908af 100644 --- a/src/string.c +++ b/src/string.c @@ -973,6 +973,8 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) switch (mrb_type(str)) { case MRB_TT_STRING: return str; + case MRB_TT_SYMBOL: + return mrb_sym2str(mrb, mrb_symbol(str)); case MRB_TT_FIXNUM: return mrb_fixnum_to_str(mrb, str, 10); case MRB_TT_CLASS: -- cgit v1.2.3 From 63d8b5e1e32cbbeb2368b06b3efa7723bf0677d2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Jun 2019 18:41:17 +0900 Subject: Fixed `mrb_iv_remove` with immediate objects; fix #4519 The #4520 tried to address the issue, but it changes the type of `mrb_check_frozen` argument; close #4520 --- src/variable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 23d900b7d..e6f2f397e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -521,11 +521,11 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) MRB_API mrb_value mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) { - mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (obj_iv_p(obj)) { iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); if (iv_del(mrb, t, sym, &val)) { return val; } -- cgit v1.2.3 From 75df13a97334c162b2cf743c3e37c4933a4b0d1c Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 25 Jun 2019 22:58:21 +0900 Subject: Fix `String#byteslice` with `MRB_UTF8_STRING` and some edge cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Example: $ bin/mruby -e ' p "あa".byteslice(1) p "bar".byteslice(3) p "bar".byteslice(4..0) ' Before this patch: "a" "" RangeError (4..0 out of range) After this patch (same as Ruby): "\x81" nil nil --- include/mruby/string.h | 3 ++ mrbgems/mruby-string-ext/src/string.c | 58 +++++++++++++-------------------- mrbgems/mruby-string-ext/test/string.rb | 51 +++++++++++++++++++++++++++++ src/string.c | 49 ++++++++++++++-------------- 4 files changed, 102 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/include/mruby/string.h b/include/mruby/string.h index 22445f654..b563541cb 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -438,6 +438,9 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); #define mrb_str_buf_cat(mrb, str, ptr, len) mrb_str_cat(mrb, str, ptr, len) #define mrb_str_buf_append(mrb, str, str2) mrb_str_cat_str(mrb, str, str2) +mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); +mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); + #ifdef MRB_UTF8_STRING mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); #endif diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index d9ebb7392..50a4e5582 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -42,44 +42,32 @@ mrb_str_setbyte(mrb_state *mrb, mrb_value str) static mrb_value mrb_str_byteslice(mrb_state *mrb, mrb_value str) { - mrb_value a1; - mrb_int len; - - if (mrb_get_argc(mrb) == 2) { - mrb_int pos; - mrb_get_args(mrb, "ii", &pos, &len); - return mrb_str_substr(mrb, str, pos, len); + mrb_value a1, a2; + mrb_int str_len = RSTRING_LEN(str), beg, len; + mrb_bool empty = TRUE; + + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 2) { + beg = mrb_fixnum(mrb_to_int(mrb, a1)); + len = mrb_fixnum(mrb_to_int(mrb, a2)); + goto subseq; } - mrb_get_args(mrb, "o|i", &a1, &len); - switch (mrb_type(a1)) { - case MRB_TT_RANGE: - { - mrb_int beg; - - len = RSTRING_LEN(str); - switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) { - case MRB_RANGE_TYPE_MISMATCH: - break; - case MRB_RANGE_OK: - return mrb_str_substr(mrb, str, beg, len); - case MRB_RANGE_OUT: - mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1); - break; - } - return mrb_nil_value(); + if (mrb_type(a1) == MRB_TT_RANGE) { + if (mrb_range_beg_len(mrb, a1, &beg, &len, str_len, TRUE) == MRB_RANGE_OK) { + goto subseq; } -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - a1 = mrb_fixnum_value((mrb_int)mrb_float(a1)); - /* fall through */ -#endif - case MRB_TT_FIXNUM: - return mrb_str_substr(mrb, str, mrb_fixnum(a1), 1); - default: - mrb_raise(mrb, E_TYPE_ERROR, "wrong type of argument"); + return mrb_nil_value(); + } + + beg = mrb_fixnum(mrb_to_int(mrb, a1)); + len = 1; + empty = FALSE; +subseq: + if (mrb_str_beg_len(str_len, &beg, &len) && (empty || len != 0)) { + return mrb_str_byte_subseq(mrb, str, beg, len); + } + else { + return mrb_nil_value(); } - /* not reached */ - return mrb_nil_value(); } /* diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 02777e594..bf633bcef 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -26,10 +26,61 @@ end assert('String#byteslice') do str1 = "hello" + str2 = "\u3042ab" # "\xE3\x81\x82ab" + + assert_equal("h", str1.byteslice(0)) assert_equal("e", str1.byteslice(1)) + assert_equal(nil, str1.byteslice(5)) assert_equal("o", str1.byteslice(-1)) + assert_equal(nil, str1.byteslice(-6)) + assert_equal("\xE3", str2.byteslice(0)) + assert_equal("\x81", str2.byteslice(1)) + assert_equal(nil, str2.byteslice(5)) + assert_equal("b", str2.byteslice(-1)) + assert_equal(nil, str2.byteslice(-6)) + + assert_equal("", str1.byteslice(0, 0)) + assert_equal(str1, str1.byteslice(0, 6)) + assert_equal("el", str1.byteslice(1, 2)) + assert_equal("", str1.byteslice(5, 1)) + assert_equal("o", str1.byteslice(-1, 6)) + assert_equal(nil, str1.byteslice(-6, 1)) + assert_equal(nil, str1.byteslice(0, -1)) + assert_equal("", str2.byteslice(0, 0)) + assert_equal(str2, str2.byteslice(0, 6)) + assert_equal("\x81\x82", str2.byteslice(1, 2)) + assert_equal("", str2.byteslice(5, 1)) + assert_equal("b", str2.byteslice(-1, 6)) + assert_equal(nil, str2.byteslice(-6, 1)) + assert_equal(nil, str2.byteslice(0, -1)) + assert_equal("ell", str1.byteslice(1..3)) assert_equal("el", str1.byteslice(1...3)) + assert_equal("h", str1.byteslice(0..0)) + assert_equal("", str1.byteslice(5..0)) + assert_equal("o", str1.byteslice(4..5)) + assert_equal(nil, str1.byteslice(6..0)) + assert_equal("", str1.byteslice(-1..0)) + assert_equal("llo", str1.byteslice(-3..5)) + assert_equal("\x81\x82a", str2.byteslice(1..3)) + assert_equal("\x81\x82", str2.byteslice(1...3)) + assert_equal("\xE3", str2.byteslice(0..0)) + assert_equal("", str2.byteslice(5..0)) + assert_equal("b", str2.byteslice(4..5)) + assert_equal(nil, str2.byteslice(6..0)) + assert_equal("", str2.byteslice(-1..0)) + assert_equal("\x82ab", str2.byteslice(-3..5)) + + assert_raise(ArgumentError) { str1.byteslice } + assert_raise(ArgumentError) { str1.byteslice(1, 2, 3) } + assert_raise(TypeError) { str1.byteslice("1") } + assert_raise(TypeError) { str1.byteslice("1", 2) } + assert_raise(TypeError) { str1.byteslice(1, "2") } + assert_raise(TypeError) { str1.byteslice(1..2, 3) } + + skip unless Object.const_defined?(:Float) + assert_equal("o", str1.byteslice(4.0)) + assert_equal("\x82ab", str2.byteslice(2.0, 3.0)) end assert('String#dump') do diff --git a/src/string.c b/src/string.c index ed58c484b..f5fb936a6 100644 --- a/src/string.c +++ b/src/string.c @@ -410,8 +410,8 @@ str_make_shared(mrb_state *mrb, struct RString *orig, struct RString *s) } } -static mrb_value -byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_value +mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { struct RString *orig, *s; @@ -434,32 +434,33 @@ str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) beg = chars2bytes(str, 0, beg); len = chars2bytes(str, beg, len); - return byte_subseq(mrb, str, beg, len); + return mrb_str_byte_subseq(mrb, str, beg, len); } #else -#define str_subseq(mrb, str, beg, len) byte_subseq(mrb, str, beg, len) +#define str_subseq(mrb, str, beg, len) mrb_str_byte_subseq(mrb, str, beg, len) #endif -static mrb_value -str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +mrb_bool +mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp) { - mrb_int clen = RSTRING_CHAR_LEN(str); - - if (len < 0) return mrb_nil_value(); - if (clen == 0) { - len = 0; + if (str_len < *begp || *lenp < 0) return FALSE; + if (*begp < 0) { + *begp += str_len; + if (*begp < 0) return FALSE; } - if (beg > clen) return mrb_nil_value(); - if (beg < 0) { - beg += clen; - if (beg < 0) return mrb_nil_value(); + if (*lenp > str_len - *begp) + *lenp = str_len - *begp; + if (*lenp <= 0) { + *lenp = 0; } - if (len > clen - beg) - len = clen - beg; - if (len <= 0) { - len = 0; - } - return str_subseq(mrb, str, beg, len); + return TRUE; +} + +static mrb_value +str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) +{ + return mrb_str_beg_len(RSTRING_CHAR_LEN(str), &beg, &len) ? + str_subseq(mrb, str, beg, len) : mrb_nil_value(); } MRB_API mrb_int @@ -1917,7 +1918,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) } } else if (ISSPACE(c)) { - mrb_ary_push(mrb, result, byte_subseq(mrb, str, beg, end-beg)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, beg, end-beg)); mrb_gc_arena_restore(mrb, ai); skip = TRUE; beg = idx; @@ -1942,7 +1943,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) else { end = chars2bytes(str, idx, 1); } - mrb_ary_push(mrb, result, byte_subseq(mrb, str, idx, end)); + mrb_ary_push(mrb, result, mrb_str_byte_subseq(mrb, str, idx, end)); mrb_gc_arena_restore(mrb, ai); idx += end + pat_len; if (lim_p && lim <= ++i) break; @@ -1954,7 +1955,7 @@ mrb_str_split_m(mrb_state *mrb, mrb_value str) tmp = mrb_str_new_empty(mrb, str); } else { - tmp = byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); + tmp = mrb_str_byte_subseq(mrb, str, beg, RSTRING_LEN(str)-beg); } mrb_ary_push(mrb, result, tmp); } -- cgit v1.2.3 From 28c510cf41767ee40dbea9b0b1f165a28da956d1 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 26 Jun 2019 15:38:20 +0900 Subject: Silence unused label warnings from gcc; ref #4524 mruby/mruby/src/string.c:1722:4: warning: label 'bytes' defined but not used [-Wunused-label] bytes: ^~~~~ --- src/string.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index b980ee760..c8a9e61ec 100644 --- a/src/string.c +++ b/src/string.c @@ -1719,12 +1719,15 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) if (RSTR_LEN(s) > 1) { mrb_str_modify(mrb, s); - bytes: - p = RSTR_PTR(s); - e = p + RSTR_LEN(s) - 1; - str_reverse(p, e); + goto bytes; } return str; + + bytes: + p = RSTR_PTR(s); + e = p + RSTR_LEN(s) - 1; + str_reverse(p, e); + return str; } /* ---------------------------------- */ -- cgit v1.2.3 From 23783a44300a39efbbc312a6ca22fe61d94db857 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 27 Jun 2019 09:34:40 +0900 Subject: Skip copying delete keys in a hash; fix #4534 --- src/hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index b4d96251c..ac6a7cd56 100644 --- a/src/hash.c +++ b/src/hash.c @@ -240,7 +240,7 @@ ht_compact(mrb_state *mrb, htable *t) if (!seg->next && i >= t->last_len) { goto exit; } - if (mrb_undef_p(k)) { /* found delete key */ + if (mrb_undef_p(k)) { /* found deleted key */ if (seg2 == NULL) { seg2 = seg; i2 = i; @@ -543,6 +543,7 @@ ht_copy(mrb_state *mrb, htable *t) mrb_value key = seg->e[i].key; mrb_value val = seg->e[i].val; + if (mrb_undef_p(key)) continue; /* skip deleted key */ if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } -- cgit v1.2.3 From c9a3867ff22a1158b88c1f9119ce3c9e08085e98 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 28 Jun 2019 19:27:58 +0900 Subject: Remove unnecessary backticks in `src/range.c`; ref #2858 --- src/range.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/range.c b/src/range.c index 9036ef093..c9dfb2b3c 100644 --- a/src/range.c +++ b/src/range.c @@ -92,7 +92,7 @@ range_ptr_init(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end, m if (r) { if (RANGE_INITIALIZED_P(r)) { /* Ranges are immutable, so that they should be initialized only once. */ - mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "'initialize' called twice"); } else { range_ptr_alloc_edges(mrb, r); -- cgit v1.2.3 From 0d452073f46fc46496200db610ce785e514cdb65 Mon Sep 17 00:00:00 2001 From: dearblue Date: Tue, 21 May 2019 22:02:11 +0900 Subject: Replace `String#[]=` method by C implements The purpose is to eliminate string objects that are temporarily created during processing. --- mrblib/string.rb | 54 ----------------- src/string.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/mrblib/string.rb b/mrblib/string.rb index b0fe4033e..c26cdb1e2 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -177,60 +177,6 @@ class String self end - ## - # Modify +self+ by replacing the content of +self+. - # The portion of the string affected is determined using the same criteria as +String#[]+. - def []=(*args) - anum = args.size - if anum == 2 - pos, value = args[0], args[1].__to_str - case pos - when String - posnum = self.index(pos) - if posnum - b = self[0, posnum] - a = self[(posnum + pos.length)..-1] - self.replace([b, value, a].join('')) - else - raise IndexError, "string not matched" - end - when Range - head = pos.begin - tail = pos.end - tail += self.length if tail < 0 - unless pos.exclude_end? - tail += 1 - end - return self[head, tail-head]=value - else - pos = pos.__to_int - pos += self.length if pos < 0 - if pos < 0 || pos > self.length - raise IndexError, "index #{args[0]} out of string" - end - b = self[0, pos] - a = self[pos + 1..-1] - self.replace([b, value, a].join('')) - end - return value - elsif anum == 3 - pos, len, value = args[0].__to_int, args[1].__to_int, args[2].__to_str - pos += self.length if pos < 0 - if pos < 0 || pos > self.length - raise IndexError, "index #{args[0]} out of string" - end - if len < 0 - raise IndexError, "negative length #{len}" - end - b = self[0, pos] - a = self[pos + len..-1] - self.replace([b, value, a].join('')) - return value - else - raise ArgumentError, "wrong number of arguments (#{anum} for 2..3)" - end - end - # those two methods requires Regexp that is optional in mruby ## # ISO 15.2.10.5.3 diff --git a/src/string.c b/src/string.c index c8a9e61ec..43bf8a841 100644 --- a/src/string.c +++ b/src/string.c @@ -427,13 +427,18 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) } return mrb_obj_value(s); } + +static void +str_range_to_bytes(mrb_value str, mrb_int *pos, mrb_int *len) +{ + *pos = chars2bytes(str, 0, *pos); + *len = chars2bytes(str, *pos, *len); +} #ifdef MRB_UTF8_STRING static inline mrb_value str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { - beg = chars2bytes(str, 0, beg); - len = chars2bytes(str, beg, len); - + str_range_to_bytes(str, &beg, &len); return mrb_str_byte_subseq(mrb, str, beg, len); } #else @@ -1010,6 +1015,68 @@ mrb_str_dup(mrb_state *mrb, mrb_value str) return str_replace(mrb, dup, s); } +enum str_convert_range { + /* `beg` and `len` are byte unit in `0 ... str.bytesize` */ + STR_BYTE_RANGE_CORRECTED = 1, + + /* `beg` and `len` are char unit in any range */ + STR_CHAR_RANGE = 2, + + /* `beg` and `len` are char unit in `0 ... str.size` */ + STR_CHAR_RANGE_CORRECTED = 3, + + /* `beg` is out of range */ + STR_OUT_OF_RANGE = -1 +}; + +static enum str_convert_range +str_convert_range(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_int *beg, mrb_int *len) +{ + if (!mrb_undef_p(alen)) { + *beg = mrb_int(mrb, indx); + *len = mrb_int(mrb, alen); + return STR_CHAR_RANGE; + } + else { + switch (mrb_type(indx)) { + case MRB_TT_FIXNUM: + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; + + case MRB_TT_STRING: + *beg = str_index_str(mrb, str, indx, 0); + if (*beg < 0) { break; } + *len = RSTRING_LEN(indx); + return STR_BYTE_RANGE_CORRECTED; + + case MRB_TT_RANGE: + goto range_arg; + + default: + indx = mrb_to_int(mrb, indx); + if (mrb_fixnum_p(indx)) { + *beg = mrb_fixnum(indx); + *len = 1; + return STR_CHAR_RANGE; + } +range_arg: + *len = RSTRING_CHAR_LEN(str); + switch (mrb_range_beg_len(mrb, indx, beg, len, *len, TRUE)) { + case MRB_RANGE_OK: + return STR_CHAR_RANGE_CORRECTED; + case MRB_RANGE_OUT: + return STR_OUT_OF_RANGE; + default: + break; + } + + mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); + } + } + return STR_OUT_OF_RANGE; +} + static mrb_value mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) { @@ -1113,6 +1180,108 @@ mrb_str_aref_m(mrb_state *mrb, mrb_value str) return mrb_str_aref(mrb, str, a1); } +static mrb_noreturn void +str_out_of_index(mrb_state *mrb, mrb_value index) +{ + mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of string", index); +} + +static mrb_value +str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb_value rep) +{ + const mrb_int shrink_threshold = 256; + struct RString *str = mrb_str_ptr(src); + mrb_int len = RSTR_LEN(str); + mrb_int replen, newlen; + char *strp; + + if (end > len) { end = len; } + + if (pos < 0 || pos > len) { + str_out_of_index(mrb, mrb_fixnum_value(pos)); + } + + replen = (mrb_nil_p(rep) ? 0 : RSTRING_LEN(rep)); + newlen = replen + len - (end - pos); + + if (newlen >= MRB_INT_MAX || newlen < replen /* overflowed */) { + mrb_raise(mrb, E_RUNTIME_ERROR, "string size too big"); + } + + mrb_str_modify(mrb, str); + + if (len < newlen || len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + + strp = RSTR_PTR(str); + + memmove(strp + newlen - (len - end), strp + end, len - end); + if (!mrb_nil_p(rep)) { + memcpy(strp + pos, RSTRING_PTR(rep), replen); + } + RSTR_SET_LEN(str, newlen); + strp[newlen] = '\0'; + + return src; +} + +static void +mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_value replace) +{ + mrb_int beg, len, charlen; + + replace = mrb_to_str(mrb, replace); + + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_OUT_OF_RANGE: + default: + mrb_raise(mrb, E_INDEX_ERROR, "string not matched"); + case STR_CHAR_RANGE: + if (len < 0) { + mrb_raisef(mrb, E_INDEX_ERROR, "negative length %S", alen); + } + charlen = RSTRING_CHAR_LEN(str); + if (beg < 0) { beg += charlen; } + if (beg < 0 || beg > charlen) { str_out_of_index(mrb, indx); } + /* fall through */ + case STR_CHAR_RANGE_CORRECTED: + str_range_to_bytes(str, &beg, &len); + /* fall through */ + case STR_BYTE_RANGE_CORRECTED: + str_replace_partial(mrb, str, beg, beg + len, replace); + } +} + +/* + * call-seq: + * str[fixnum] = replace + * str[fixnum, fixnum] = replace + * str[range] = replace + * str[regexp] = replace + * str[regexp, fixnum] = replace + * str[other_str] = replace + * + * Modify +self+ by replacing the content of +self+. + * The portion of the string affected is determined using the same criteria as +String#[]+. + */ +static mrb_value +mrb_str_aset_m(mrb_state *mrb, mrb_value str) +{ + mrb_value indx, alen, replace; + + switch (mrb_get_args(mrb, "oo|S!", &indx, &alen, &replace)) { + case 2: + replace = alen; + alen = mrb_undef_value(); + break; + case 3: + break; + } + mrb_str_aset(mrb, str, indx, alen, replace); + return str; +} + /* 15.2.10.5.8 */ /* * call-seq: @@ -2678,6 +2847,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "+", mrb_str_plus_m, MRB_ARGS_REQ(1)); /* 15.2.10.5.4 */ mrb_define_method(mrb, s, "*", mrb_str_times, MRB_ARGS_REQ(1)); /* 15.2.10.5.5 */ mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY()); /* 15.2.10.5.6 */ + mrb_define_method(mrb, s, "[]=", mrb_str_aset_m, MRB_ARGS_ANY()); mrb_define_method(mrb, s, "capitalize", mrb_str_capitalize, MRB_ARGS_NONE()); /* 15.2.10.5.7 */ mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ -- cgit v1.2.3 From 0ad1cacff30c744fcf07869990cbab7bc51c4c68 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 27 Jun 2019 20:46:49 +0900 Subject: Simplify `mrb_str_aref_m()` and `mrb_str_aref()` It is integration with part of argument parsing used in `mrb_str_aset_m()`. --- src/string.c | 66 ++++++++++++++++++------------------------------------------ 1 file changed, 20 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 43bf8a841..6938418fb 100644 --- a/src/string.c +++ b/src/string.c @@ -1078,50 +1078,28 @@ range_arg: } static mrb_value -mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx) +mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen) { - mrb_int idx; + mrb_int beg, len; - switch (mrb_type(indx)) { - case MRB_TT_FIXNUM: - idx = mrb_fixnum(indx); - -num_index: - str = str_substr(mrb, str, idx, 1); - if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); + switch (str_convert_range(mrb, str, indx, alen, &beg, &len)) { + case STR_CHAR_RANGE_CORRECTED: + return str_subseq(mrb, str, beg, len); + case STR_CHAR_RANGE: + str = str_substr(mrb, str, beg, len); + if (mrb_undef_p(alen) && !mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value(); return str; - - case MRB_TT_STRING: - if (str_index_str(mrb, str, indx, 0) != -1) + case STR_BYTE_RANGE_CORRECTED: + if (mrb_string_p(indx)) { return mrb_str_dup(mrb, indx); - return mrb_nil_value(); - - case MRB_TT_RANGE: - goto range_arg; - - default: - indx = mrb_Integer(mrb, indx); - if (mrb_nil_p(indx)) { - range_arg: - { - mrb_int beg, len; - - len = RSTRING_CHAR_LEN(str); - switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { - case MRB_RANGE_OK: - return str_subseq(mrb, str, beg, len); - case MRB_RANGE_OUT: - return mrb_nil_value(); - default: - break; - } - } - mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); } - idx = mrb_fixnum(indx); - goto num_index; + else { + return mrb_str_byte_subseq(mrb, str, beg, len); + } + case STR_OUT_OF_RANGE: + default: + return mrb_nil_value(); } - return mrb_nil_value(); /* not reached */ } /* 15.2.10.5.6 */ @@ -1168,16 +1146,12 @@ static mrb_value mrb_str_aref_m(mrb_state *mrb, mrb_value str) { mrb_value a1, a2; - mrb_int argc; - argc = mrb_get_args(mrb, "o|o", &a1, &a2); - if (argc == 2) { - mrb_int n1, n2; - - mrb_get_args(mrb, "ii", &n1, &n2); - return str_substr(mrb, str, n1, n2); + if (mrb_get_args(mrb, "o|o", &a1, &a2) == 1) { + a2 = mrb_undef_value(); } - return mrb_str_aref(mrb, str, a1); + + return mrb_str_aref(mrb, str, a1, a2); } static mrb_noreturn void -- cgit v1.2.3 From 97c9e6b00032cd8a7132b43911c05e44732a4c56 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 30 Jun 2019 14:46:38 +0900 Subject: Fix `include`, `prepend` and `extend` to frozen object --- src/class.c | 5 +++-- test/t/kernel.rb | 3 +++ test/t/module.rb | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 373f2aec7..1064870a8 100644 --- a/src/class.c +++ b/src/class.c @@ -1070,8 +1070,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, find_origin(c), m, 1); - if (changed < 0) { + mrb_check_frozen(mrb, c); + if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } } @@ -1082,6 +1082,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; + mrb_check_frozen(mrb, c); if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 1e48069f2..ecfb863a8 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -240,6 +240,9 @@ assert('Kernel#extend', '15.3.1.3.13') do assert_true a.respond_to?(:test_method) assert_false b.respond_to?(:test_method) + + assert_raise(FrozenError) { Object.new.freeze.extend(Test4ExtendModule) } + assert_raise(FrozenError, TypeError) { :sym.extend(Test4ExtendModule) } end assert('Kernel#extend works on toplevel', '15.3.1.3.13') do diff --git a/test/t/module.rb b/test/t/module.rb index 571f4759d..7f869bf1f 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -59,6 +59,7 @@ assert('Module#append_features', '15.2.2.4.10') do end assert_equal Test4AppendFeatures2, Test4AppendFeatures2.const_get(:Const4AppendFeatures2) + assert_raise(FrozenError) { Module.new.append_features Class.new.freeze } end assert('Module#attr NameError') do @@ -275,6 +276,18 @@ assert('Module#const_missing', '15.2.2.4.22') do assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist) end +assert('Module#extend_object', '15.2.2.4.25') do + cls = Class.new + mod = Module.new { def foo; end } + a = cls.new + b = cls.new + mod.extend_object(b) + assert_false a.respond_to?(:foo) + assert_true b.respond_to?(:foo) + assert_raise(FrozenError) { mod.extend_object(cls.new.freeze) } + assert_raise(FrozenError, TypeError) { mod.extend_object(1) } +end + assert('Module#include', '15.2.2.4.27') do module Test4Include Const4Include = 42 @@ -288,6 +301,7 @@ assert('Module#include', '15.2.2.4.27') do assert_equal 42, Test4Include2.const_get(:Const4Include) assert_equal Test4Include2, Test4Include2.include_result + assert_raise(FrozenError) { Module.new.freeze.include Test4Include } end assert('Module#include?', '15.2.2.4.28') do @@ -398,6 +412,15 @@ assert('Module#define_method') do end end +assert 'Module#prepend_features' do + mod = Module.new { def m; :mod end } + cls = Class.new { def m; :cls end } + assert_equal :cls, cls.new.m + mod.prepend_features(cls) + assert_equal :mod, cls.new.m + assert_raise(FrozenError) { Module.new.prepend_features(Class.new.freeze) } +end + # @!group prepend assert('Module#prepend') do module M0 @@ -632,6 +655,10 @@ end # end # end; #end + + assert 'Module#prepend to frozen class' do + assert_raise(FrozenError) { Class.new.freeze.prepend Module.new } + end # @!endgroup prepend assert('Module#to_s') do -- cgit v1.2.3 From 7e3a8b7a7520b101d8cc3453cf7ca5e3c7700772 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 1 Jul 2019 12:29:02 +0900 Subject: Remove unused C header file from `src/etc.c` --- src/etc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/etc.c b/src/etc.c index ac1540f92..37717a6f2 100644 --- a/src/etc.c +++ b/src/etc.c @@ -1,5 +1,5 @@ /* -** etc.c - +** etc.c ** ** See Copyright Notice in mruby.h */ @@ -8,8 +8,6 @@ #include #include #include -#include -#include MRB_API struct RData* mrb_data_object_alloc(mrb_state *mrb, struct RClass *klass, void *ptr, const mrb_data_type *type) -- cgit v1.2.3 From 0d54dbb2644b468e255564cfdbb5c435e1e3686f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 2 Jul 2019 19:41:40 +0900 Subject: Fix and refine error message in `mrb_obj_to_sym()` Before this patch: $ bin/mruby -e '1.respond_to?(2)' #=> nil is not a symbol After this patch (same as Ruby): $ bin/mruby -e '1.respond_to?(2)' #=> 2 is not a symbol nor a string --- src/etc.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/etc.c b/src/etc.c index 37717a6f2..18d2839d9 100644 --- a/src/etc.c +++ b/src/etc.c @@ -65,24 +65,10 @@ mrb_data_get_ptr(mrb_state *mrb, mrb_value obj, const mrb_data_type *type) MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name) { - mrb_sym id; - - switch (mrb_type(name)) { - default: - name = mrb_check_string_type(mrb, name); - if (mrb_nil_p(name)) { - name = mrb_inspect(mrb, name); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); - /* not reached */ - } - /* fall through */ - case MRB_TT_STRING: - name = mrb_str_intern(mrb, name); - /* fall through */ - case MRB_TT_SYMBOL: - id = mrb_symbol(name); - } - return id; + if (mrb_symbol_p(name)) return mrb_symbol(name); + if (mrb_string_p(name)) return mrb_intern_str(mrb, name); + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol nor a string", mrb_inspect(mrb, name)); + return 0; /* not reached */ } MRB_API mrb_int -- cgit v1.2.3 From d915261590d646a8788b2200342228804cb1754f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 3 Jul 2019 20:36:04 +0900 Subject: Refine document to mrb_get_args()` [ci skip] --- include/mruby.h | 12 +++++++----- src/class.c | 16 ++++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 3ef399716..7deb3cbe2 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -836,15 +836,17 @@ MRB_API struct RClass * mrb_define_module_under(mrb_state *mrb, struct RClass *o * | `S` | {String} | {mrb_value} | when `!` follows, the value may be `nil` | * | `A` | {Array} | {mrb_value} | when `!` follows, the value may be `nil` | * | `H` | {Hash} | {mrb_value} | when `!` follows, the value may be `nil` | - * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` | + * | `s` | {String} | char *, {mrb_int} | Receive two arguments; `s!` gives (`NULL`,`0`) for `nil` | * | `z` | {String} | char * | `NULL` terminated string; `z!` gives `NULL` for `nil` | * | `a` | {Array} | {mrb_value} *, {mrb_int} | Receive two arguments; `a!` gives (`NULL`,`0`) for `nil` | - * | `f` | {Float} | {mrb_float} | | - * | `i` | {Integer} | {mrb_int} | | + * | `f` | {Fixnum}/{Float} | {mrb_float} | | + * | `i` | {Fixnum}/{Float} | {mrb_int} | | * | `b` | boolean | {mrb_bool} | | - * | `n` | {Symbol} | {mrb_sym} | | + * | `n` | {String}/{Symbol} | {mrb_sym} | | + * | `d` | data | void *, {mrb_data_type} const | 2nd argument will be used to check data type so it won't be modified; when `!` follows, the value may be `nil` | + * | `I` | inline struct | void * | | * | `&` | block | {mrb_value} | &! raises exception if no block given. | - * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; *! avoid copy of the stack. | + * | `*` | rest arguments | {mrb_value} *, {mrb_int} | Receive the rest of arguments as an array; `*!` avoid copy of the stack. | * | | | optional | | After this spec following specs would be optional. | * | `?` | optional given | {mrb_bool} | `TRUE` if preceding argument is given. Used to check optional argument is given. | * diff --git a/src/class.c b/src/class.c index 1064870a8..edee95678 100644 --- a/src/class.c +++ b/src/class.c @@ -573,20 +573,20 @@ mrb_get_argv(mrb_state *mrb) string mruby type C type note ---------------------------------------------------------------------------------------------- o: Object [mrb_value] - C: class/module [mrb_value] + C: Class/Module [mrb_value] S: String [mrb_value] when ! follows, the value may be nil A: Array [mrb_value] when ! follows, the value may be nil H: Hash [mrb_value] when ! follows, the value may be nil s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil z: String [char*] NUL terminated string; z! gives NULL for nil a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil - f: Float [mrb_float] - i: Integer [mrb_int] - b: Boolean [mrb_bool] - n: Symbol [mrb_sym] - d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified - I: Inline struct [void*] - &: Block [mrb_value] &! raises exception if no block given + f: Fixnum/Float [mrb_float] + i: Fixnum/Float [mrb_int] + b: boolean [mrb_bool] + n: String/Symbol [mrb_sym] + d: data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil + I: inline struct [void*] + &: block [mrb_value] &! raises exception if no block given *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack |: optional Following arguments are optional ?: optional given [mrb_bool] true if preceding argument (optional) is given -- cgit v1.2.3 From 2bb30481b6d6aed0f869dd089a56ebe24e8e2349 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 4 Jul 2019 21:49:07 +0900 Subject: Fix heap buffer overflow; ref #4549 This patch is showed in #4549. --- src/string.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 6938418fb..7a094b3a7 100644 --- a/src/string.c +++ b/src/string.c @@ -1184,7 +1184,7 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb mrb_str_modify(mrb, str); - if (len < newlen || len - newlen >= shrink_threshold) { + if (len < newlen) { resize_capa(mrb, str, newlen); } @@ -1197,6 +1197,10 @@ str_replace_partial(mrb_state *mrb, mrb_value src, mrb_int pos, mrb_int end, mrb RSTR_SET_LEN(str, newlen); strp[newlen] = '\0'; + if (len - newlen >= shrink_threshold) { + resize_capa(mrb, str, newlen); + } + return src; } -- cgit v1.2.3 From 991bdd4ed7b0aa6fd6bee4fa5c62283365dcf15d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 4 Jul 2019 23:01:16 +0900 Subject: Rename `MRB_STR_NO_UTF` to 'MRB_STR_ASCII`; close #4550 In #4550, @shuuji proposed the name name `MRB_STR_NO_MULTI_BYTE` for more precise description. Although I agree that the name name is correct, but the flag means the string does not contain multi byte UTF-8 characters, i.e. all characters fit in the range of ASCII. --- include/mruby/string.h | 2 +- src/string.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/include/mruby/string.h b/include/mruby/string.h index b563541cb..9484e20d7 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -87,7 +87,7 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_FSHARED 2 #define MRB_STR_NOFREE 4 #define MRB_STR_POOL 8 -#define MRB_STR_NO_UTF 16 +#define MRB_STR_ASCII 16 #define MRB_STR_EMBED 32 #define MRB_STR_EMBED_LEN_MASK 0x7c0 #define MRB_STR_EMBED_LEN_SHIFT 6 diff --git a/src/string.c b/src/string.c index 7a094b3a7..805cf01dc 100644 --- a/src/string.c +++ b/src/string.c @@ -260,12 +260,12 @@ utf8_strlen(mrb_value str) { mrb_int byte_len = RSTRING_LEN(str); - if (RSTRING(str)->flags & MRB_STR_NO_UTF) { + if (RSTRING(str)->flags & MRB_STR_ASCII) { return byte_len; } else { mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); - if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_NO_UTF; + if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_ASCII; return utf8_len; } } @@ -512,8 +512,8 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); - s1->flags &= ~MRB_STR_NO_UTF; - s1->flags |= s2->flags&MRB_STR_NO_UTF; + s1->flags &= ~MRB_STR_ASCII; + s1->flags |= s2->flags&MRB_STR_ASCII; len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -651,7 +651,7 @@ MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - s->flags &= ~MRB_STR_NO_UTF; + s->flags &= ~MRB_STR_ASCII; if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; -- cgit v1.2.3 From 8294ce9fd458a0a1acf8fcdcb6161b4a020866ad Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 4 Jul 2019 23:11:57 +0900 Subject: It was too early to check `key` for `undef`; ref #4534 --- src/hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index ac6a7cd56..2a0a19363 100644 --- a/src/hash.c +++ b/src/hash.c @@ -543,10 +543,10 @@ ht_copy(mrb_state *mrb, htable *t) mrb_value key = seg->e[i].key; mrb_value val = seg->e[i].val; - if (mrb_undef_p(key)) continue; /* skip deleted key */ if ((seg->next == NULL) && (i >= t->last_len)) { return t2; } + if (mrb_undef_p(key)) continue; /* skip deleted key */ ht_put(mrb, t2, key, val); } seg = seg->next; -- cgit v1.2.3 From f9bf2d9d8e2531b2bfebb5a80362b43ab559b56f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 5 Jul 2019 20:37:59 +0900 Subject: Read/write `MRB_STR_ASCII` flag only when `MRB_UTF8_STRING` is defined --- include/mruby/string.h | 14 ++++++++++++++ src/string.c | 14 +++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/include/mruby/string.h b/include/mruby/string.h index 9484e20d7..d648d856c 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -68,6 +68,20 @@ struct RString { #define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE) #define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE) +#ifdef MRB_UTF8_STRING +# define RSTR_ASCII_P(s) ((s)->flags & MRB_STR_ASCII) +# define RSTR_SET_ASCII_FLAG(s) ((s)->flags |= MRB_STR_ASCII) +# define RSTR_UNSET_ASCII_FLAG(s) ((s)->flags &= ~MRB_STR_ASCII) +# define RSTR_WRITE_ASCII_FLAG(s, v) (RSTR_UNSET_ASCII_FLAG(s), (s)->flags |= v) +# define RSTR_COPY_ASCII_FLAG(dst, src) RSTR_WRITE_ASCII_FLAG(dst, RSTR_ASCII_P(src)) +#else +# define RSTR_ASCII_P(s) (void)0 +# define RSTR_SET_ASCII_FLAG(s) (void)0 +# define RSTR_UNSET_ASCII_FLAG(s) (void)0 +# define RSTR_WRITE_ASCII_FLAG(s, v) (void)0 +# define RSTR_COPY_ASCII_FLAG(dst, src) (void)0 +#endif + #define RSTR_POOL_P(s) ((s)->flags & MRB_STR_POOL) #define RSTR_SET_POOL_FLAG(s) ((s)->flags |= MRB_STR_POOL) diff --git a/src/string.c b/src/string.c index 805cf01dc..078c028d8 100644 --- a/src/string.c +++ b/src/string.c @@ -258,14 +258,15 @@ mrb_utf8_len(const char *str, mrb_int byte_len) static mrb_int utf8_strlen(mrb_value str) { - mrb_int byte_len = RSTRING_LEN(str); + struct RString *s = mrb_str_ptr(str); + mrb_int byte_len = RSTR_LEN(s); - if (RSTRING(str)->flags & MRB_STR_ASCII) { + if (RSTR_ASCII_P(s)) { return byte_len; } else { - mrb_int utf8_len = mrb_utf8_len(RSTRING_PTR(str), byte_len); - if (byte_len == utf8_len) RSTRING(str)->flags |= MRB_STR_ASCII; + mrb_int utf8_len = mrb_utf8_len(RSTR_PTR(s), byte_len); + if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s); return utf8_len; } } @@ -512,8 +513,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) mrb_check_frozen(mrb, s1); if (s1 == s2) return mrb_obj_value(s1); - s1->flags &= ~MRB_STR_ASCII; - s1->flags |= s2->flags&MRB_STR_ASCII; + RSTR_COPY_ASCII_FLAG(s1, s2); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); @@ -651,7 +651,7 @@ MRB_API void mrb_str_modify(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - s->flags &= ~MRB_STR_ASCII; + RSTR_UNSET_ASCII_FLAG(s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; -- cgit v1.2.3 From df1f1002d9fe8466e0d621818febf465e03b9016 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 6 Jul 2019 19:55:37 +0900 Subject: Fix missing `#ifndef MRB_ENABLE_ALL_SYMBOLS` --- src/symbol.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index b26f2b1fd..5eeb28045 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -503,9 +503,11 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ +#ifndef MRB_ENABLE_ALL_SYMBOLS if (sym&1) { /* inline symbol */ return mrb_str_new(mrb, name, len); } +#endif return mrb_str_new_static(mrb, name, len); } @@ -521,12 +523,12 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) } else { mrb_value str; - if (sym&1) { /* inline symbol */ +#ifndef MRB_ENABLE_ALL_SYMBOLS + if (sym&1) /* inline symbol */ str = mrb_str_new(mrb, name, len); - } - else { + else +#endif str = mrb_str_new_static(mrb, name, len); - } str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } -- cgit v1.2.3 From 0a79486380d6991cf6adc015de65d9758d1584e3 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 8 Jul 2019 22:14:23 +0900 Subject: Add macros for inline symbol for readability --- src/symbol.c | 65 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 5eeb28045..38843c71f 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -20,6 +20,22 @@ typedef struct symbol_name { const char *name; } symbol_name; +#define SYMBOL_INLINE_BIT 1 +#define SYMBOL_INLINE_LOWER_BIT 2 +#define SYMBOL_INLINE (1 << (SYMBOL_INLINE_BIT - 1)) +#define SYMBOL_INLINE_LOWER (1 << (SYMBOL_INLINE_LOWER_BIT - 1)) +#define SYMBOL_NORMAL_SHIFT SYMBOL_INLINE_BIT +#define SYMBOL_INLINE_SHIFT SYMBOL_INLINE_LOWER_BIT +#ifdef MRB_ENABLE_ALL_SYMBOLS +# define SYMBOL_INLINE_P(sym) FALSE +# define SYMBOL_INLINE_LOWER_P(sym) FALSE +# define sym_inline_pack(name, len) 0 +# define sym_inline_unpack(sym, buf, lenp) NULL +#else +# define SYMBOL_INLINE_P(sym) ((sym) & SYMBOL_INLINE) +# define SYMBOL_INLINE_LOWER_P(sym) ((sym) & SYMBOL_INLINE_LOWER) +#endif + static void sym_validate_len(mrb_state *mrb, size_t len) { @@ -41,7 +57,7 @@ sym_inline_pack(const char *name, uint16_t len) const char *p; int i; mrb_sym sym = 0; - int lower = 1; + mrb_bool lower = TRUE; if (len > lower_length_max) return 0; /* too long */ for (i=0; i 27) lower = 0; + if (bits > 27) lower = FALSE; if (i >= mix_length_max) break; - sym |= bits<<(i*6+2); + sym |= bits<<(i*6+SYMBOL_INLINE_SHIFT); } if (lower) { sym = 0; @@ -64,24 +80,24 @@ sym_inline_pack(const char *name, uint16_t len) c = name[i]; p = strchr(pack_table, (int)c); bits = (uint32_t)(p - pack_table)+1; - sym |= bits<<(i*5+2); + sym |= bits<<(i*5+SYMBOL_INLINE_SHIFT); } - return sym | 3; + return sym | SYMBOL_INLINE | SYMBOL_INLINE_LOWER; } if (len > mix_length_max) return 0; - return sym | 1; + return sym | SYMBOL_INLINE; } static const char* sym_inline_unpack(mrb_sym sym, char *buf, mrb_int *lenp) { - int bit_per_char = sym&2 ? 5 : 6; /* all lower case if `sym&2` is true */ + int bit_per_char = SYMBOL_INLINE_LOWER_P(sym) ? 5 : 6; int i; - mrb_assert(sym&1); + mrb_assert(SYMBOL_INLINE_P(sym)); for (i=0; i<30/bit_per_char; i++) { - uint32_t bits = sym>>(i*bit_per_char+2) & ((1<>(i*bit_per_char+SYMBOL_INLINE_SHIFT) & ((1< 0) return i; -#endif i = mrb->symhash[hash]; if (i == 0) return 0; do { sname = &mrb->symtbl[i]; if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return i<<1; + return i<prev == 0xff) { i -= 0xff; sname = &mrb->symtbl[i]; while (mrb->symtbl < sname) { if (sname->len == len && memcmp(sname->name, name, len) == 0) { - return (mrb_sym)(sname - mrb->symtbl)<<1; + return (mrb_sym)(sname - mrb->symtbl)<symhash[hash] = sym; - return sym<<1; + return sym<>= 1; + sym >>= SYMBOL_NORMAL_SHIFT; if (sym == 0 || mrb->symidx < sym) { if (lenp) *lenp = 0; return NULL; @@ -503,11 +513,7 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ -#ifndef MRB_ENABLE_ALL_SYMBOLS - if (sym&1) { /* inline symbol */ - return mrb_str_new(mrb, name, len); - } -#endif + if (SYMBOL_INLINE_P(sym)) return mrb_str_new(mrb, name, len); return mrb_str_new_static(mrb, name, len); } @@ -522,13 +528,8 @@ mrb_sym2name(mrb_state *mrb, mrb_sym sym) return name; } else { - mrb_value str; -#ifndef MRB_ENABLE_ALL_SYMBOLS - if (sym&1) /* inline symbol */ - str = mrb_str_new(mrb, name, len); - else -#endif - str = mrb_str_new_static(mrb, name, len); + mrb_value str = SYMBOL_INLINE_P(sym) ? + mrb_str_new(mrb, name, len) : mrb_str_new_static(mrb, name, len); str = mrb_str_dump(mrb, str); return RSTRING_PTR(str); } -- cgit v1.2.3 From 23fc3339eedf685e358c9389b4f6b8bd068bcad2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 9 Jul 2019 18:59:00 +0900 Subject: Set `MRB_STR_ASCII` flag when an inline symbol is stringized --- src/symbol.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/symbol.c b/src/symbol.c index 38843c71f..53f4f6e1d 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -494,7 +494,7 @@ sym_inspect(mrb_state *mrb, mrb_value sym) name = mrb_sym2name_len(mrb, id, &len); str = mrb_str_new(mrb, 0, len+1); sp = RSTRING_PTR(str); - RSTRING_PTR(str)[0] = ':'; + sp[0] = ':'; memcpy(sp+1, name, len); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); if (!symname_p(name) || strlen(name) != (size_t)len) { @@ -503,6 +503,9 @@ sym_inspect(mrb_state *mrb, mrb_value sym) sp[0] = ':'; sp[1] = '"'; } +#ifdef MRB_UTF8_STRING + if (SYMBOL_INLINE_P(id)) RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); +#endif return str; } @@ -513,7 +516,11 @@ mrb_sym2str(mrb_state *mrb, mrb_sym sym) const char *name = mrb_sym2name_len(mrb, sym, &len); if (!name) return mrb_undef_value(); /* can't happen */ - if (SYMBOL_INLINE_P(sym)) return mrb_str_new(mrb, name, len); + if (SYMBOL_INLINE_P(sym)) { + mrb_value str = mrb_str_new(mrb, name, len); + RSTR_SET_ASCII_FLAG(mrb_str_ptr(str)); + return str; + } return mrb_str_new_static(mrb, name, len); } -- cgit v1.2.3 From 80f78ca196790e2900b89f447c5ab83433d69d89 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 10 Jul 2019 21:53:17 +0900 Subject: Remove an unused argument of `str_with_class()` --- src/string.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 078c028d8..3ef86eb53 100644 --- a/src/string.c +++ b/src/string.c @@ -83,7 +83,7 @@ str_new(mrb_state *mrb, const char *p, size_t len) } static inline void -str_with_class(mrb_state *mrb, struct RString *s, mrb_value obj) +str_with_class(struct RString *s, mrb_value obj) { s->c = mrb_str_ptr(obj)->c; } @@ -93,7 +93,7 @@ mrb_str_new_empty(mrb_state *mrb, mrb_value str) { struct RString *s = str_new(mrb, 0, 0); - str_with_class(mrb, s, str); + str_with_class(s, str); return mrb_obj_value(s); } @@ -830,7 +830,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) len = RSTRING_LEN(self)*times; str2 = str_new(mrb, 0, len); - str_with_class(mrb, str2, self); + str_with_class(str2, self); p = RSTR_PTR(str2); if (len > 0) { n = RSTRING_LEN(self); @@ -1011,7 +1011,7 @@ mrb_str_dup(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); struct RString *dup = str_new(mrb, 0, 0); - str_with_class(mrb, dup, str); + str_with_class(dup, str); return str_replace(mrb, dup, s); } @@ -2561,7 +2561,7 @@ mrb_str_dump(mrb_state *mrb, mrb_value str) } result = str_new(mrb, 0, len); - str_with_class(mrb, result, str); + str_with_class(result, str); p = RSTRING_PTR(str); pend = p + RSTRING_LEN(str); q = RSTR_PTR(result); *q++ = '"'; -- cgit v1.2.3 From 8c0d9ba1a363683bbeab8cb7c22acdb07621352d Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 11 Jul 2019 21:52:05 +0900 Subject: Improve performance `String#index` with UTF-8 Based on Boyer-Moore-Horspool algorithm (Quick Search algorithm). As a side effect, the correct position is returned even if an invalid UTF-8 string is given. ```console % ./mruby@master -e 'p ("\xd1" * 100 + "#").index("#")' 50 % ./mruby@improve-index -e 'p ("\xd1" * 100 + "#").index("#")' 100 ``` The other behavior should be the same as the current implementation. --- src/string.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 3ef86eb53..0700f81fa 100644 --- a/src/string.c +++ b/src/string.c @@ -304,12 +304,73 @@ bytes2chars(char *p, mrb_int bi) return i; } +static mrb_int +str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, const char *s, const mrb_int slen, mrb_int off) +{ + /* Based on Quick Search algorithm (Boyer-Moore-Horspool algorithm) */ + + ptrdiff_t qstable[1 << CHAR_BIT]; + + /* Preprocessing */ + { + size_t i; + + for (i = 0; i < 1 << CHAR_BIT; i ++) { + qstable[i] = slen; + } + for (i = 0; i < slen; i ++) { + qstable[(unsigned char)s[i]] = slen - (i + 1); + } + } + + /* Searching */ + if (p < pend && pend - p >= slen) { + for (;;) { + const char *pivot; + + if (memcmp(p, s, slen) == 0) { + return off; + } + + pivot = p + qstable[(unsigned char)p[slen - 1]]; + if (pivot > pend || pivot < p /* overflowed */) { return -1; } + + do { + p += utf8len(p, pend); + off ++; + } while (p < pivot); + } + } + + return -1; +} + +static mrb_int +str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos) +{ + const char *p = RSTRING_PTR(str); + const char *pend = p + RSTRING_LEN(str); + const char *s = RSTRING_PTR(sub); + const mrb_int slen = RSTRING_LEN(sub); + mrb_int off = pos; + + for (; pos > 0; pos --) { + if (pend - p < 1) { return -1; } + p += utf8len(p, pend); + } + + if (slen < 1) { return off; } + + return str_index_str_by_char_search(mrb, p, pend, s, slen, off); +} + #define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value(); #else #define RSTRING_CHAR_LEN(s) RSTRING_LEN(s) #define chars2bytes(p, off, ci) (ci) #define bytes2chars(p, bi) (bi) #define BYTES_ALIGN_CHECK(pos) +#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos) #endif static inline mrb_int @@ -1680,15 +1741,13 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) else sub = mrb_nil_value(); } - clen = RSTRING_CHAR_LEN(str); if (pos < 0) { + clen = RSTRING_CHAR_LEN(str); pos += clen; if (pos < 0) { return mrb_nil_value(); } } - if (pos > clen) return mrb_nil_value(); - pos = chars2bytes(str, 0, pos); switch (mrb_type(sub)) { default: { @@ -1702,12 +1761,11 @@ mrb_str_index_m(mrb_state *mrb, mrb_value str) } /* fall through */ case MRB_TT_STRING: - pos = str_index_str(mrb, str, sub, pos); + pos = str_index_str_by_char(mrb, str, sub, pos); break; } if (pos == -1) return mrb_nil_value(); - pos = bytes2chars(RSTRING_PTR(str), pos); BYTES_ALIGN_CHECK(pos); return mrb_fixnum_value(pos); } -- cgit v1.2.3 From bde2f35a9f2d894ec88ad693633e89279b0560b9 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 12 Jul 2019 21:23:55 +0900 Subject: Fix heap buffer overflow; fix #4569 --- src/string.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 0700f81fa..056348921 100644 --- a/src/string.c +++ b/src/string.c @@ -324,22 +324,20 @@ str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, co } /* Searching */ - if (p < pend && pend - p >= slen) { - for (;;) { - const char *pivot; + while (p < pend && pend - p >= slen) { + const char *pivot; - if (memcmp(p, s, slen) == 0) { - return off; - } + if (memcmp(p, s, slen) == 0) { + return off; + } - pivot = p + qstable[(unsigned char)p[slen - 1]]; - if (pivot > pend || pivot < p /* overflowed */) { return -1; } + pivot = p + qstable[(unsigned char)p[slen - 1]]; + if (pivot > pend || pivot < p /* overflowed */) { return -1; } - do { - p += utf8len(p, pend); - off ++; - } while (p < pivot); - } + do { + p += utf8len(p, pend); + off ++; + } while (p < pivot); } return -1; -- cgit v1.2.3 From 6b1cc6e2fe4eab30e265d8209a208e0bf942c54d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 8 Jul 2019 18:40:13 +0900 Subject: Avoid `mrb_funcall()` if possible using `mrb_Float()`; ref #4555 --- src/numeric.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 0d1c23589..4288df44a 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -172,17 +172,17 @@ integral_div(mrb_state *mrb, mrb_value x) static mrb_value integral_coerce_step_counter(mrb_state *mrb, mrb_value self) { - mrb_value counter = self, num, step; + mrb_value num, step; mrb_get_args(mrb, "oo", &num, &step); #ifndef MRB_WITHOUT_FLOAT if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { - counter = mrb_funcall(mrb, counter, "to_f", 0); + return mrb_Float(mrb, self); } #endif - return counter; + return self; } #ifndef MRB_WITHOUT_FLOAT -- cgit v1.2.3 From 9741df100bb84a858725dba58705a908e5bdca4c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 13 Jul 2019 13:13:21 +0900 Subject: Change type of a variable for signedness mismatch; ref #4573 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 056348921..a6aa9d906 100644 --- a/src/string.c +++ b/src/string.c @@ -313,7 +313,7 @@ str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, co /* Preprocessing */ { - size_t i; + mrb_int i; for (i = 0; i < 1 << CHAR_BIT; i ++) { qstable[i] = slen; -- cgit v1.2.3 From 7b260d9c2de4436d6e8b09ba4fd524782934153f Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 14 Jul 2019 18:55:38 +0900 Subject: Improve `utf8len()` performance with UTF-8 --- src/string.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index a6aa9d906..be623deda 100644 --- a/src/string.c +++ b/src/string.c @@ -233,7 +233,9 @@ utf8len(const char* p, const char* e) mrb_int len; mrb_int i; + if ((unsigned char)*p < 0x80) return 1; len = utf8len_codepage[(unsigned char)*p]; + if (len == 1) return 1; if (len > e - p) return 1; for (i = 1; i < len; ++i) if ((p[i] & 0xc0) != 0x80) -- cgit v1.2.3 From 380805ece257147275bbed3eb83277f374296d9a Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 14 Jul 2019 19:13:19 +0900 Subject: Keep `MRB_STR_ASCII` flag in some methods of `String` --- include/mruby/string.h | 9 ++++++++- src/string.c | 15 +++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/include/mruby/string.h b/include/mruby/string.h index d648d856c..4615b4384 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -107,7 +107,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_EMBED_LEN_SHIFT 6 void mrb_gc_free_str(mrb_state*, struct RString*); -MRB_API void mrb_str_modify(mrb_state*, struct RString*); /* * Finds the index of a substring in a string @@ -454,6 +453,14 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); +void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); + +MRB_INLINE void +mrb_str_modify(mrb_state *mrb, struct RString *s) +{ + mrb_str_modify_keep_ascii(mrb, s); + RSTR_UNSET_ASCII_FLAG(s); +} #ifdef MRB_UTF8_STRING mrb_int mrb_utf8_len(const char *str, mrb_int byte_len); diff --git a/src/string.c b/src/string.c index a6aa9d906..8706bfd1b 100644 --- a/src/string.c +++ b/src/string.c @@ -706,11 +706,10 @@ mrb_locale_from_utf8(const char *utf8, int len) } #endif -MRB_API void -mrb_str_modify(mrb_state *mrb, struct RString *s) +void +mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); - RSTR_UNSET_ASCII_FLAG(s); if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; @@ -1339,7 +1338,7 @@ mrb_str_capitalize_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) == 0 || !RSTR_PTR(s)) return mrb_nil_value(); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); if (ISLOWER(*p)) { @@ -1398,7 +1397,7 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) struct RString *s = mrb_str_ptr(str); argc = mrb_get_args(mrb, "|S", &rs); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); len = RSTR_LEN(s); if (argc == 0) { if (len == 0) return mrb_nil_value(); @@ -1497,7 +1496,7 @@ mrb_str_chop_bang(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); if (RSTR_LEN(s) > 0) { mrb_int len; #ifdef MRB_UTF8_STRING @@ -1566,7 +1565,7 @@ mrb_str_downcase_bang(mrb_state *mrb, mrb_value str) mrb_bool modify = FALSE; struct RString *s = mrb_str_ptr(str); - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTR_PTR(s); pend = RSTR_PTR(s) + RSTR_LEN(s); while (p < pend) { @@ -2536,7 +2535,7 @@ mrb_str_upcase_bang(mrb_state *mrb, mrb_value str) char *p, *pend; mrb_bool modify = FALSE; - mrb_str_modify(mrb, s); + mrb_str_modify_keep_ascii(mrb, s); p = RSTRING_PTR(str); pend = RSTRING_END(str); while (p < pend) { -- cgit v1.2.3 From 9093f3403f76b0a70d2b29b6c04ca7f203c242e6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 15 Jul 2019 07:39:57 +0900 Subject: Add `MRB_API` to `mrb_str_modify_keep_ascii()` --- include/mruby/string.h | 3 ++- src/string.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/mruby/string.h b/include/mruby/string.h index 4615b4384..77f6becf6 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -108,6 +108,8 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); void mrb_gc_free_str(mrb_state*, struct RString*); +MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); + /* * Finds the index of a substring in a string */ @@ -453,7 +455,6 @@ mrb_value mrb_str_inspect(mrb_state *mrb, mrb_value str); mrb_bool mrb_str_beg_len(mrb_int str_len, mrb_int *begp, mrb_int *lenp); mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); -void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s); MRB_INLINE void mrb_str_modify(mrb_state *mrb, struct RString *s) diff --git a/src/string.c b/src/string.c index 8706bfd1b..c1a001634 100644 --- a/src/string.c +++ b/src/string.c @@ -706,7 +706,7 @@ mrb_locale_from_utf8(const char *utf8, int len) } #endif -void +MRB_API void mrb_str_modify_keep_ascii(mrb_state *mrb, struct RString *s) { mrb_check_frozen(mrb, s); -- cgit v1.2.3 From acad9567c16317a86d7e246d6093a43d3a58c758 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 15 Jul 2019 23:03:41 +0900 Subject: Unify type of line number to `uint16_t` --- include/mruby/compile.h | 6 +++--- mrbgems/mruby-compiler/core/parse.y | 2 +- mrbgems/mruby-eval/src/eval.c | 2 +- src/backtrace.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/include/mruby/compile.h b/include/mruby/compile.h index 8f8f2ebd7..3b25ff526 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -24,7 +24,7 @@ typedef struct mrbc_context { mrb_sym *syms; int slen; char *filename; - short lineno; + uint16_t lineno; int (*partial_hook)(struct mrb_parser_state*); void *partial_data; struct RClass *target_class; @@ -67,7 +67,7 @@ enum mrb_lex_state_enum { /* saved error message */ struct mrb_parser_message { - int lineno; + uint16_t lineno; int column; char* message; }; @@ -119,7 +119,7 @@ struct mrb_parser_state { #endif mrbc_context *cxt; mrb_sym filename_sym; - int lineno; + uint16_t lineno; int column; enum mrb_lex_state_enum lstate; diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 96a9453b6..ac59a8b0b 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -233,7 +233,7 @@ parser_strdup(parser_state *p, const char *s) #define strdup(s) parser_strdup(p, s) static void -dump_int(short i, char *s) +dump_int(uint16_t i, char *s) { char *p = s; char *t = s; diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index a3b211ba2..30534aaec 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -235,7 +235,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, } cxt = mrbc_context_new(mrb); - cxt->lineno = (short)line; + cxt->lineno = (uint16_t)line; mrbc_filename(mrb, cxt, file ? file : "(eval)"); cxt->capture_errors = TRUE; diff --git a/src/backtrace.c b/src/backtrace.c index e4f5a3064..991a67d00 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -16,7 +16,7 @@ #include struct backtrace_location { - int lineno; + int32_t lineno; mrb_sym method_id; const char *filename; }; -- cgit v1.2.3 From 31492a177c34485e9bcc441e74c208366920f7b2 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 16 Jul 2019 21:56:58 +0900 Subject: Copy receiver's `MRB_STR_ASCII` flag in some methods of `String` --- src/string.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index 39b3515a3..6b7cced13 100644 --- a/src/string.c +++ b/src/string.c @@ -487,6 +487,7 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) s->as.heap.ptr += beg; s->as.heap.len = len; } + RSTR_COPY_ASCII_FLAG(s, orig); return mrb_obj_value(s); } @@ -902,6 +903,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) memcpy(p + n, p, len-n); } p[RSTR_LEN(str2)] = '\0'; + RSTR_COPY_ASCII_FLAG(str2, mrb_str_ptr(self)); return mrb_obj_value(str2); } @@ -2837,6 +2839,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } } mrb_str_cat_lit(mrb, result, "\""); + RSTR_COPY_ASCII_FLAG(mrb_str_ptr(result), mrb_str_ptr(str)); return result; } -- cgit v1.2.3