modules/mruby/src/vm.c in webruby-0.2.7 vs modules/mruby/src/vm.c in webruby-0.9.1
- old
+ new
@@ -1,26 +1,28 @@
- /*
+/*
** vm.c - virtual machine for mruby
**
** See Copyright Notice in mruby.h
*/
-#include <setjmp.h>
#include <stddef.h>
#include <stdarg.h>
+#include <math.h>
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/hash.h"
#include "mruby/irep.h"
+#include "mruby/numeric.h"
#include "mruby/proc.h"
#include "mruby/range.h"
#include "mruby/string.h"
#include "mruby/variable.h"
-#include "error.h"
-#include "opcode.h"
+#include "mruby/error.h"
+#include "mruby/opcode.h"
#include "value_array.h"
+#include "mrb_throw.h"
#ifndef ENABLE_STDIO
#if defined(__cplusplus)
extern "C" {
#endif
@@ -28,24 +30,10 @@
#if defined(__cplusplus)
} /* extern "C" { */
#endif
#endif
-#define SET_TRUE_VALUE(r) MRB_SET_VALUE(r, MRB_TT_TRUE, value.i, 1)
-#define SET_FALSE_VALUE(r) MRB_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
-#define SET_NIL_VALUE(r) MRB_SET_VALUE(r, MRB_TT_FALSE, value.i, 0)
-#define SET_INT_VALUE(r,n) MRB_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
-#define SET_SYM_VALUE(r,v) MRB_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
-#define SET_OBJ_VALUE(r,v) MRB_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
-#ifdef MRB_NAN_BOXING
-#define SET_FLT_VALUE(mrb,r,v) r.f = (v)
-#elif defined(MRB_WORD_BOXING)
-#define SET_FLT_VALUE(mrb,r,v) r = mrb_float_value(mrb, (v))
-#else
-#define SET_FLT_VALUE(mrb,r,v) MRB_SET_VALUE(r, MRB_TT_FLOAT, value.f, (v))
-#endif
-
#define STACK_INIT_SIZE 128
#define CALLINFO_INIT_SIZE 32
/* Define amount of linear stack growth. */
#ifndef MRB_STACK_GROWTH
@@ -62,13 +50,10 @@
# define DEBUG(x) (x)
#else
# define DEBUG(x)
#endif
-#define TO_STR(x) TO_STR_(x)
-#define TO_STR_(x) #x
-
#define ARENA_RESTORE(mrb,ai) (mrb)->arena_idx = (ai)
static inline void
stack_clear(mrb_value *from, size_t count)
{
@@ -107,66 +92,84 @@
/* mrb_assert(ci == NULL); */
c->cibase = (mrb_callinfo *)mrb_calloc(mrb, CALLINFO_INIT_SIZE, sizeof(mrb_callinfo));
c->ciend = c->cibase + CALLINFO_INIT_SIZE;
c->ci = c->cibase;
c->ci->target_class = mrb->object_class;
+ c->ci->stackent = c->stack;
}
static inline void
envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase)
{
mrb_callinfo *ci = mrb->c->cibase;
+ if (newbase == oldbase) return;
while (ci <= mrb->c->ci) {
struct REnv *e = ci->env;
- if (e && e->cioff >= 0) {
+ if (e && MRB_ENV_STACK_SHARED_P(e)) {
ptrdiff_t off = e->stack - oldbase;
e->stack = newbase + off;
}
+ ci->stackent = newbase + (ci->stackent - oldbase);
ci++;
}
}
+static inline void
+init_new_stack_space(mrb_state *mrb, int room, int keep)
+{
+ if (room > keep) {
+ /* do not leave uninitialized malloc region */
+ stack_clear(&(mrb->c->stack[keep]), room - keep);
+ }
+}
+
/** 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, int room, int keep)
{
mrb_value *oldbase = mrb->c->stbase;
int size = mrb->c->stend - mrb->c->stbase;
int off = mrb->c->stack - mrb->c->stbase;
+#ifdef MRB_STACK_EXTEND_DOUBLING
+ if (room <= size)
+ size *= 2;
+ else
+ size += room;
+#else
/* Use linear stack growth.
It is slightly slower than doubling the stack space,
but it saves memory on small devices. */
- if (room <= size)
+ if (room <= MRB_STACK_GROWTH)
size += MRB_STACK_GROWTH;
else
size += room;
+#endif
mrb->c->stbase = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
mrb->c->stack = mrb->c->stbase + off;
mrb->c->stend = mrb->c->stbase + size;
envadjust(mrb, oldbase, mrb->c->stbase);
+
/* Raise an exception if the new stack size will be too large,
to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
if (size > MRB_STACK_MAX) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "stack level too deep. (limit=" TO_STR(MRB_STACK_MAX) ")");
+ init_new_stack_space(mrb, room, keep);
+ mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")");
}
}
static inline void
stack_extend(mrb_state *mrb, int room, int keep)
{
if (mrb->c->stack + room >= mrb->c->stend) {
- stack_extend_alloc(mrb, room);
+ stack_extend_alloc(mrb, room, keep);
}
- if (room > keep) {
- /* do not leave uninitialized malloc region */
- stack_clear(&(mrb->c->stack[keep]), room - keep);
- }
+ init_new_stack_space(mrb, room, keep);
}
static inline struct REnv*
uvenv(mrb_state *mrb, int up)
{
@@ -182,11 +185,11 @@
static inline mrb_bool
is_strict(mrb_state *mrb, struct REnv *e)
{
int cioff = e->cioff;
- if (cioff >= 0 && mrb->c->cibase[cioff].proc &&
+ if (MRB_ENV_STACK_SHARED_P(e) && mrb->c->cibase[cioff].proc &&
MRB_PROC_STRICT_P(mrb->c->cibase[cioff].proc)) {
return TRUE;
}
return FALSE;
}
@@ -222,16 +225,16 @@
c->cibase = (mrb_callinfo *)mrb_realloc(mrb, c->cibase, sizeof(mrb_callinfo)*size*2);
c->ci = c->cibase + size;
c->ciend = c->cibase + size * 2;
}
ci = ++c->ci;
- ci->nregs = 2; /* protect method_missing arg and block */
ci->eidx = eidx;
ci->ridx = ridx;
ci->env = 0;
ci->pc = 0;
ci->err = 0;
+ ci->proc = 0;
return ci;
}
static void
@@ -239,16 +242,19 @@
{
struct mrb_context *c = mrb->c;
if (c->ci->env) {
struct REnv *e = c->ci->env;
- size_t len = (size_t)e->flags;
+ size_t len = (size_t)MRB_ENV_STACK_LEN(e);
mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
- e->cioff = -1;
- stack_copy(p, e->stack, len);
+ MRB_ENV_UNSHARE_STACK(e);
+ if (len > 0) {
+ stack_copy(p, e->stack, len);
+ }
e->stack = p;
+ mrb_write_barrier(mrb, (struct RBasic *)e);
}
c->ci--;
}
@@ -263,11 +269,11 @@
p = mrb->c->ensure[i];
if (!p) return;
if (mrb->c->ci->eidx > i)
mrb->c->ci->eidx = i;
ci = cipush(mrb);
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
ci->mid = ci[-1].mid;
ci->acc = CI_ACC_SKIP;
ci->argc = 0;
ci->proc = p;
ci->nregs = p->body.irep->nregs;
@@ -281,68 +287,54 @@
#ifndef MRB_FUNCALL_ARGC_MAX
#define MRB_FUNCALL_ARGC_MAX 16
#endif
-mrb_value
-mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, int argc, ...)
+MRB_API mrb_value
+mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...)
{
+ mrb_value argv[MRB_FUNCALL_ARGC_MAX];
+ va_list ap;
+ mrb_int i;
mrb_sym mid = mrb_intern_cstr(mrb, name);
- if (argc == 0) {
- return mrb_funcall_argv(mrb, self, mid, 0, 0);
+ if (argc > MRB_FUNCALL_ARGC_MAX) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" MRB_STRINGIZE(MRB_FUNCALL_ARGC_MAX) ")");
}
- else if (argc == 1) {
- mrb_value v;
- va_list ap;
- va_start(ap, argc);
- v = va_arg(ap, mrb_value);
- va_end(ap);
- return mrb_funcall_argv(mrb, self, mid, 1, &v);
+ va_start(ap, argc);
+ for (i = 0; i < argc; i++) {
+ argv[i] = va_arg(ap, mrb_value);
}
- else {
- mrb_value argv[MRB_FUNCALL_ARGC_MAX];
- va_list ap;
- int i;
-
- if (argc > MRB_FUNCALL_ARGC_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" TO_STR(MRB_FUNCALL_ARGC_MAX) ")");
- }
-
- va_start(ap, argc);
- for (i = 0; i < argc; i++) {
- argv[i] = va_arg(ap, mrb_value);
- }
- va_end(ap);
- return mrb_funcall_argv(mrb, self, mid, argc, argv);
- }
+ va_end(ap);
+ return mrb_funcall_argv(mrb, self, mid, argc, argv);
}
-mrb_value
-mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mrb_value *argv, mrb_value blk)
+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)
{
mrb_value val;
if (!mrb->jmp) {
- jmp_buf c_jmp;
+ struct mrb_jmpbuf c_jmp;
mrb_callinfo *old_ci = mrb->c->ci;
- if (setjmp(c_jmp) != 0) { /* error */
+ MRB_TRY(&c_jmp) {
+ mrb->jmp = &c_jmp;
+ /* recursive call */
+ val = mrb_funcall_with_block(mrb, self, mid, argc, argv, blk);
+ mrb->jmp = 0;
+ }
+ MRB_CATCH(&c_jmp) { /* error */
while (old_ci != mrb->c->ci) {
- mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
}
mrb->jmp = 0;
val = mrb_obj_value(mrb->exc);
}
- else {
- mrb->jmp = &c_jmp;
- /* recursive call */
- val = mrb_funcall_with_block(mrb, self, mid, argc, argv, blk);
- mrb->jmp = 0;
- }
+ MRB_END_EXC(&c_jmp);
}
else {
struct RProc *p;
struct RClass *c;
mrb_sym undef = 0;
@@ -365,26 +357,28 @@
n++; argc++;
}
ci = cipush(mrb);
ci->mid = mid;
ci->proc = p;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
ci->argc = argc;
ci->target_class = c;
+ mrb->c->stack = mrb->c->stack + n;
if (MRB_PROC_CFUNC_P(p)) {
ci->nregs = argc + 2;
+ stack_extend(mrb, ci->nregs, 0);
}
else {
ci->nregs = p->body.irep->nregs + n;
+ stack_extend(mrb, ci->nregs, argc+2);
}
- mrb->c->stack = mrb->c->stack + n;
-
- stack_extend(mrb, ci->nregs, 0);
mrb->c->stack[0] = self;
if (undef) {
mrb->c->stack[1] = mrb_symbol_value(undef);
- stack_copy(mrb->c->stack+2, argv, argc-1);
+ if (argc > 1) {
+ stack_copy(mrb->c->stack+2, argv, argc-1);
+ }
}
else if (argc > 0) {
stack_copy(mrb->c->stack+1, argv, argc);
}
mrb->c->stack[argc+1] = blk;
@@ -392,11 +386,11 @@
if (MRB_PROC_CFUNC_P(p)) {
int ai = mrb_gc_arena_save(mrb);
ci->acc = CI_ACC_DIRECT;
val = p->body.func(mrb, self);
- mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
mrb_gc_arena_restore(mrb, ai);
}
else {
ci->acc = CI_ACC_SKIP;
@@ -405,19 +399,184 @@
}
mrb_gc_protect(mrb, val);
return val;
}
-mrb_value
-mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mrb_value *argv)
+MRB_API mrb_value
+mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv)
{
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
+/* 15.3.1.3.4 */
+/* 15.3.1.3.44 */
+/*
+ * call-seq:
+ * obj.send(symbol [, args...]) -> obj
+ * obj.__send__(symbol [, args...]) -> obj
+ *
+ * Invokes the method identified by _symbol_, passing it any
+ * arguments specified. You can use <code>__send__</code> if the name
+ * +send+ clashes with an existing method in _obj_.
+ *
+ * class Klass
+ * def hello(*args)
+ * "Hello " + args.join(' ')
+ * end
+ * end
+ * k = Klass.new
+ * k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
+ */
+MRB_API mrb_value
+mrb_f_send(mrb_state *mrb, mrb_value self)
+{
+ mrb_sym name;
+ mrb_value block, *argv, *regs;
+ mrb_int argc, i, len;
+ struct RProc *p;
+ struct RClass *c;
+ mrb_callinfo *ci;
+
+ mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);
+
+ c = mrb_class(mrb, self);
+ p = mrb_method_search_vm(mrb, &c, name);
+
+ if (!p) { /* call method_mising */
+ return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
+ }
+
+ ci = mrb->c->ci;
+ ci->mid = name;
+ ci->target_class = c;
+ ci->proc = p;
+ regs = mrb->c->stack+1;
+ /* remove first symbol from arguments */
+ if (ci->argc >= 0) {
+ for (i=0,len=ci->argc; i<len; i++) {
+ regs[i] = regs[i+1];
+ }
+ ci->argc--;
+ }
+ else { /* variable length arguments */
+ mrb_ary_shift(mrb, regs[0]);
+ }
+
+ if (MRB_PROC_CFUNC_P(p)) {
+ return p->body.func(mrb, self);
+ }
+
+ ci->nregs = p->body.irep->nregs;
+ ci = cipush(mrb);
+ ci->nregs = 0;
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
+static mrb_value
+eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
+{
+ struct RProc *p;
+ mrb_callinfo *ci;
+
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ ci = mrb->c->ci;
+ if (ci->acc == CI_ACC_DIRECT) {
+ return mrb_yield_with_class(mrb, blk, 0, 0, self, c);
+ }
+ ci->target_class = c;
+ p = mrb_proc_ptr(blk);
+ ci->proc = p;
+ if (MRB_PROC_CFUNC_P(p)) {
+ return p->body.func(mrb, self);
+ }
+ ci->nregs = p->body.irep->nregs;
+ ci = cipush(mrb);
+ ci->nregs = 0;
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
+/* 15.2.2.4.35 */
+/*
+ * call-seq:
+ * mod.class_eval {| | block } -> obj
+ * mod.module_eval {| | block } -> obj
+ *
+ * Evaluates block in the context of _mod_. This can
+ * be used to add methods to a class. <code>module_eval</code> returns
+ * the result of evaluating its argument.
+ */
mrb_value
-mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c)
+mrb_mod_module_eval(mrb_state *mrb, mrb_value mod)
{
+ mrb_value a, b;
+
+ if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
+ mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented");
+ }
+ return eval_under(mrb, mod, b, mrb_class_ptr(mod));
+}
+
+/* 15.3.1.3.18 */
+/*
+ * call-seq:
+ * obj.instance_eval {| | block } -> obj
+ *
+ * Evaluates the given block,within the context of the receiver (_obj_).
+ * In order to set the context, the variable +self+ is set to _obj_ while
+ * the code is executing, giving the code access to _obj_'s
+ * instance variables. In the version of <code>instance_eval</code>
+ * that takes a +String+, the optional second and third
+ * parameters supply a filename and starting line number that are used
+ * when reporting compilation errors.
+ *
+ * class KlassWithSecret
+ * def initialize
+ * @secret = 99
+ * end
+ * end
+ * k = KlassWithSecret.new
+ * k.instance_eval { @secret } #=> 99
+ */
+mrb_value
+mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
+{
+ mrb_value a, b;
+ mrb_value cv;
+ struct RClass *c;
+
+ if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
+ mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented");
+ }
+ switch (mrb_type(self)) {
+ case MRB_TT_SYMBOL:
+ case MRB_TT_FIXNUM:
+ case MRB_TT_FLOAT:
+ c = 0;
+ break;
+ default:
+ cv = mrb_singleton_class(mrb, self);
+ c = mrb_class_ptr(cv);
+ break;
+ }
+ return eval_under(mrb, self, b, c);
+}
+
+MRB_API mrb_value
+mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c)
+{
struct RProc *p;
mrb_sym mid = mrb->c->ci->mid;
mrb_callinfo *ci;
int n = mrb->c->ci->nregs;
mrb_value val;
@@ -427,54 +586,55 @@
}
p = mrb_proc_ptr(b);
ci = cipush(mrb);
ci->mid = mid;
ci->proc = p;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
ci->argc = argc;
ci->target_class = c;
+ ci->acc = CI_ACC_SKIP;
+ mrb->c->stack = mrb->c->stack + n;
if (MRB_PROC_CFUNC_P(p)) {
ci->nregs = argc + 2;
+ stack_extend(mrb, ci->nregs, 0);
}
else {
- ci->nregs = p->body.irep->nregs + 1;
+ ci->nregs = p->body.irep->nregs;
+ stack_extend(mrb, ci->nregs, argc+2);
}
- ci->acc = CI_ACC_SKIP;
- mrb->c->stack = mrb->c->stack + n;
- stack_extend(mrb, ci->nregs, 0);
mrb->c->stack[0] = self;
if (argc > 0) {
stack_copy(mrb->c->stack+1, argv, argc);
}
mrb->c->stack[argc+1] = mrb_nil_value();
if (MRB_PROC_CFUNC_P(p)) {
val = p->body.func(mrb, self);
- mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
}
else {
val = mrb_run(mrb, p, self);
}
return val;
}
-mrb_value
-mrb_yield_argv(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv)
+MRB_API mrb_value
+mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv)
{
struct RProc *p = mrb_proc_ptr(b);
- return mrb_yield_internal(mrb, b, argc, argv, p->env->stack[0], p->target_class);
+ return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class);
}
-mrb_value
+MRB_API mrb_value
mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg)
{
struct RProc *p = mrb_proc_ptr(b);
- return mrb_yield_internal(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
+ return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
}
typedef enum {
LOCALJUMP_ERROR_RETURN = 0,
LOCALJUMP_ERROR_BREAK = 1,
@@ -489,18 +649,18 @@
static const char lead[] = "unexpected ";
mrb_value msg;
mrb_value exc;
msg = mrb_str_buf_new(mrb, sizeof(lead) + 7);
- mrb_str_buf_cat(mrb, msg, lead, sizeof(lead) - 1);
- mrb_str_buf_cat(mrb, msg, kind_str[kind], kind_str_len[kind]);
+ mrb_str_cat(mrb, msg, lead, sizeof(lead) - 1);
+ mrb_str_cat(mrb, msg, kind_str[kind], kind_str_len[kind]);
exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
mrb->exc = mrb_obj_ptr(exc);
}
static void
-argnum_error(mrb_state *mrb, int num)
+argnum_error(mrb_state *mrb, mrb_int num)
{
mrb_value exc;
mrb_value str;
if (mrb->c->ci->mid) {
@@ -522,11 +682,11 @@
#define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs));
#else
#define CODE_FETCH_HOOK(mrb, irep, pc, regs)
#endif
-#ifdef __GNUC__
+#if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER
#define DIRECT_THREADED
#endif
#ifndef DIRECT_THREADED
@@ -550,23 +710,23 @@
mrb_value mrb_gv_val_get(mrb_state *mrb, mrb_sym sym);
void mrb_gv_val_set(mrb_state *mrb, mrb_sym sym, mrb_value val);
#define CALL_MAXARGS 127
-mrb_value
+MRB_API mrb_value
mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
/* mrb_assert(mrb_proc_cfunc_p(proc)) */
mrb_irep *irep = proc->body.irep;
mrb_code *pc = irep->iseq;
mrb_value *pool = irep->pool;
mrb_sym *syms = irep->syms;
mrb_value *regs = NULL;
mrb_code i;
int ai = mrb_gc_arena_save(mrb);
- jmp_buf *prev_jmp = (jmp_buf *)mrb->jmp;
- jmp_buf c_jmp;
+ struct mrb_jmpbuf *prev_jmp = mrb->jmp;
+ struct mrb_jmpbuf c_jmp;
#ifdef DIRECT_THREADED
static void *optable[] = {
&&L_OP_NOP, &&L_OP_MOVE,
&&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL,
@@ -589,23 +749,26 @@
&&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS,
&&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR,
};
#endif
+ mrb_bool exc_catched = FALSE;
+RETRY_TRY_BLOCK:
- if (setjmp(c_jmp) == 0) {
- mrb->jmp = &c_jmp;
- }
- else {
+ MRB_TRY(&c_jmp) {
+
+ if (exc_catched) {
+ exc_catched = FALSE;
goto L_RAISE;
}
+ mrb->jmp = &c_jmp;
if (!mrb->c->stack) {
stack_init(mrb);
}
stack_extend(mrb, irep->nregs, stack_keep);
mrb->c->ci->proc = proc;
- mrb->c->ci->nregs = irep->nregs + 1;
+ mrb->c->ci->nregs = irep->nregs;
regs = mrb->c->stack;
regs[0] = self;
INIT_DISPATCH {
CASE(OP_NOP) {
@@ -619,22 +782,22 @@
NEXT;
}
CASE(OP_LOADL) {
/* A Bx R(A) := Pool(Bx) */
- regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
+ regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
NEXT;
}
CASE(OP_LOADI) {
- /* A Bx R(A) := sBx */
+ /* A sBx R(A) := sBx */
SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i));
NEXT;
}
CASE(OP_LOADSYM) {
- /* A B R(A) := Sym(B) */
+ /* A Bx R(A) := Syms(Bx) */
SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]);
NEXT;
}
CASE(OP_LOADSELF) {
@@ -654,17 +817,17 @@
SET_FALSE_VALUE(regs[GETARG_A(i)]);
NEXT;
}
CASE(OP_GETGLOBAL) {
- /* A B R(A) := getglobal(Sym(B)) */
+ /* A Bx R(A) := getglobal(Syms(Bx)) */
regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]);
NEXT;
}
CASE(OP_SETGLOBAL) {
- /* setglobal(Sym(b), R(A)) */
+ /* setglobal(Syms(Bx), R(A)) */
mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
NEXT;
}
CASE(OP_GETSPECIAL) {
@@ -684,31 +847,31 @@
regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]);
NEXT;
}
CASE(OP_SETIV) {
- /* ivset(Sym(B),R(A)) */
+ /* ivset(Syms(Bx),R(A)) */
mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
NEXT;
}
CASE(OP_GETCV) {
- /* A B R(A) := ivget(Sym(B)) */
+ /* A Bx R(A) := cvget(Syms(Bx)) */
ERR_PC_SET(mrb, pc);
regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]);
ERR_PC_CLR(mrb);
NEXT;
}
CASE(OP_SETCV) {
- /* ivset(Sym(B),R(A)) */
+ /* cvset(Syms(Bx),R(A)) */
mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
NEXT;
}
CASE(OP_GETCONST) {
- /* A B R(A) := constget(Sym(B)) */
+ /* A Bx R(A) := constget(Syms(Bx)) */
mrb_value val;
ERR_PC_SET(mrb, pc);
val = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
ERR_PC_CLR(mrb);
@@ -716,17 +879,17 @@
regs[GETARG_A(i)] = val;
NEXT;
}
CASE(OP_SETCONST) {
- /* A B constset(Sym(B),R(A)) */
+ /* A Bx constset(Syms(Bx),R(A)) */
mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
NEXT;
}
CASE(OP_GETMCNST) {
- /* A B C R(A) := R(C)::Sym(B) */
+ /* A Bx R(A) := R(A)::Syms(Bx) */
mrb_value val;
int a = GETARG_A(i);
ERR_PC_SET(mrb, pc);
val = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
@@ -735,11 +898,11 @@
regs[a] = val;
NEXT;
}
CASE(OP_SETMCNST) {
- /* A B C R(A+1)::Sym(B) := R(A) */
+ /* A Bx R(A+1)::Syms(Bx) := R(A) */
int a = GETARG_A(i);
mrb_const_set(mrb, regs[a+1], syms[GETARG_Bx(i)], regs[a]);
NEXT;
}
@@ -761,11 +924,10 @@
NEXT;
}
CASE(OP_SETUPVAR) {
/* A B C uvset(B,C,R(A)) */
- /* A B C R(A) := uvget(B,C) */
int up = GETARG_C(i);
struct REnv *e = uvenv(mrb, up);
if (e) {
@@ -791,11 +953,11 @@
}
NEXT;
}
CASE(OP_JMPNOT) {
- /* A sBx if R(A) pc+=sBx */
+ /* A sBx if !R(A) pc+=sBx */
if (!mrb_test(regs[GETARG_A(i)])) {
pc += GETARG_sBx(i);
JUMP;
}
NEXT;
@@ -818,10 +980,11 @@
mrb->exc = 0;
NEXT;
}
CASE(OP_POPERR) {
+ /* A A.times{rescue_pop()} */
int a = GETARG_A(i);
while (a--) {
mrb->c->ci->ridx--;
}
@@ -862,24 +1025,25 @@
}
NEXT;
}
CASE(OP_LOADNIL) {
- /* A B R(A) := nil */
+ /* A R(A) := nil */
int a = GETARG_A(i);
SET_NIL_VALUE(regs[a]);
NEXT;
}
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 */
};
L_SEND:
CASE(OP_SEND) {
- /* A B C R(A) := call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */
+ /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */
int a = GETARG_A(i);
int n = GETARG_C(i);
struct RProc *m;
struct RClass *c;
mrb_callinfo *ci;
@@ -913,51 +1077,43 @@
/* push callinfo */
ci = cipush(mrb);
ci->mid = mid;
ci->proc = m;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
- if (n == CALL_MAXARGS) {
- ci->argc = -1;
- }
- else {
- ci->argc = n;
- }
- if (c->tt == MRB_TT_ICLASS) {
- ci->target_class = c->c;
- }
- else {
- ci->target_class = c;
- }
+ ci->stackent = mrb->c->stack;
+ ci->target_class = c;
ci->pc = pc + 1;
ci->acc = a;
/* prepare stack */
mrb->c->stack += a;
if (MRB_PROC_CFUNC_P(m)) {
if (n == CALL_MAXARGS) {
+ ci->argc = -1;
ci->nregs = 3;
}
else {
+ ci->argc = n;
ci->nregs = n + 2;
}
result = m->body.func(mrb, recv);
mrb->c->stack[0] = result;
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
ci = mrb->c->ci;
if (!ci->target_class) { /* return from context modifying method (resume/yield) */
if (!MRB_PROC_CFUNC_P(ci[-1].proc)) {
- irep = ci[-1].proc->body.irep;
+ proc = ci[-1].proc;
+ irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
}
}
- regs = mrb->c->stack = mrb->c->stbase + ci->stackidx;
+ regs = mrb->c->stack = ci->stackent;
pc = ci->pc;
cipop(mrb);
JUMP;
}
else {
@@ -965,24 +1121,26 @@
proc = mrb->c->ci->proc = m;
irep = m->body.irep;
pool = irep->pool;
syms = irep->syms;
ci->nregs = irep->nregs;
- if (ci->argc < 0) {
+ if (n == CALL_MAXARGS) {
+ ci->argc = -1;
stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
}
else {
- stack_extend(mrb, irep->nregs, ci->argc+2);
+ ci->argc = n;
+ stack_extend(mrb, irep->nregs, n+2);
}
regs = mrb->c->stack;
pc = irep->iseq;
JUMP;
}
}
CASE(OP_FSEND) {
- /* A B C R(A) := fcall(R(A),Sym(B),R(A+1),... ,R(A+C)) */
+ /* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */
NEXT;
}
CASE(OP_CALL) {
/* A R(A) := self.call(frame.argc, frame.argv) */
@@ -1008,11 +1166,11 @@
recv = m->body.func(mrb, recv);
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
ci = mrb->c->ci;
- regs = mrb->c->stack = mrb->c->stbase + ci->stackidx;
+ regs = mrb->c->stack = ci->stackent;
regs[ci->acc] = recv;
pc = ci->pc;
cipop(mrb);
irep = mrb->c->ci->proc->body.irep;
pool = irep->pool;
@@ -1032,21 +1190,21 @@
ci->nregs = irep->nregs;
if (ci->argc < 0) {
stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
}
else {
- stack_extend(mrb, irep->nregs, ci->argc+2);
+ stack_extend(mrb, irep->nregs, ci->argc+2);
}
regs = mrb->c->stack;
regs[0] = m->env->stack[0];
- pc = m->body.irep->iseq;
+ pc = irep->iseq;
JUMP;
}
}
CASE(OP_SUPER) {
- /* A B C R(A) := super(R(A+1),... ,R(A+C-1)) */
+ /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */
mrb_value recv;
mrb_callinfo *ci = mrb->c->ci;
struct RProc *m;
struct RClass *c;
mrb_sym mid = ci->mid;
@@ -1070,11 +1228,11 @@
/* push callinfo */
ci = cipush(mrb);
ci->mid = mid;
ci->proc = m;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
if (n == CALL_MAXARGS) {
ci->argc = -1;
}
else {
ci->argc = n;
@@ -1085,15 +1243,21 @@
/* prepare stack */
mrb->c->stack += a;
mrb->c->stack[0] = recv;
if (MRB_PROC_CFUNC_P(m)) {
+ if (n == CALL_MAXARGS) {
+ ci->nregs = 3;
+ }
+ else {
+ ci->nregs = n + 2;
+ }
mrb->c->stack[0] = m->body.func(mrb, recv);
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
- regs = mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ regs = mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
NEXT;
}
else {
/* fill callinfo */
@@ -1107,11 +1271,11 @@
ci->nregs = irep->nregs;
if (n == CALL_MAXARGS) {
stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
}
else {
- stack_extend(mrb, irep->nregs, ci->argc+2);
+ stack_extend(mrb, irep->nregs, ci->argc+2);
}
regs = mrb->c->stack;
pc = irep->iseq;
JUMP;
}
@@ -1130,12 +1294,11 @@
if (lv == 0) stack = regs + 1;
else {
struct REnv *e = uvenv(mrb, lv-1);
if (!e) {
mrb_value exc;
- static const char m[] = "super called outside of method";
- exc = mrb_exc_new(mrb, E_NOMETHOD_ERROR, m, sizeof(m) - 1);
+ exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
stack = e->stack + 1;
}
@@ -1153,11 +1316,13 @@
pp = ary->ptr;
len = ary->len;
}
regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
rest = mrb_ary_ptr(regs[a]);
- stack_copy(rest->ptr, stack, m1);
+ if (m1 > 0) {
+ stack_copy(rest->ptr, stack, m1);
+ }
if (len > 0) {
stack_copy(rest->ptr+m1, pp, len);
}
if (m2 > 0) {
stack_copy(rest->ptr+m1+len, stack+m1+1, m2);
@@ -1168,28 +1333,31 @@
ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_ENTER) {
- /* Ax arg setup according to flags (24=5:5:1:5:5:1:1) */
+ /* 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 = (ax>>18)&0x1f;
- int o = (ax>>13)&0x1f;
- int r = (ax>>12)&0x1;
- int m2 = (ax>>7)&0x1f;
+ int m1 = MRB_ASPEC_REQ(ax);
+ int o = MRB_ASPEC_OPT(ax);
+ int r = MRB_ASPEC_REST(ax);
+ int m2 = MRB_ASPEC_POST(ax);
/* unused
- int k = (ax>>2)&0x1f;
- int kd = (ax>>1)&0x1;
- int b = (ax>>0)& 0x1;
+ int k = MRB_ASPEC_KEY(ax);
+ int kd = MRB_ASPEC_KDICT(ax);
+ int b = MRB_ASPEC_BLOCK(ax);
*/
int argc = mrb->c->ci->argc;
mrb_value *argv = regs+1;
mrb_value *argv0 = argv;
int len = m1 + o + r + m2;
mrb_value *blk = &argv[argc < 0 ? 1 : argc];
+ if (!mrb_nil_p(*blk) && mrb_type(*blk) != MRB_TT_PROC) {
+ *blk = mrb_convert_type(mrb, *blk, MRB_TT_PROC, "Proc", "to_proc");
+ }
if (argc < 0) {
struct RArray *ary = mrb_ary_ptr(regs[1]);
argv = ary->ptr;
argc = ary->len;
mrb_gc_protect(mrb, regs[1]);
@@ -1201,44 +1369,51 @@
goto L_RAISE;
}
}
}
else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
+ mrb_gc_protect(mrb, argv[0]);
argc = mrb_ary_ptr(argv[0])->len;
argv = mrb_ary_ptr(argv[0])->ptr;
}
mrb->c->ci->argc = len;
if (argc < len) {
+ int mlen = m2;
+ if (argc < m1+m2) {
+ if (m1 < argc)
+ mlen = argc - m1;
+ else
+ mlen = 0;
+ }
regs[len+1] = *blk; /* move block */
+ SET_NIL_VALUE(regs[argc+1]);
if (argv0 != argv) {
- value_move(®s[1], argv, argc-m2); /* m1 + o */
+ value_move(®s[1], argv, argc-mlen); /* m1 + o */
}
- if (m2) {
- int mlen = m2;
- if (argc-m2 <= m1) {
- mlen = argc - m1;
- }
+ if (mlen) {
value_move(®s[len-m2+1], &argv[argc-mlen], mlen);
}
if (r) {
regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
}
- if (o == 0) pc++;
+ if (o == 0 || argc < m1+m2) pc++;
else
pc += argc - m1 - m2 + 1;
}
else {
+ int rnum = 0;
if (argv0 != argv) {
regs[len+1] = *blk; /* move block */
value_move(®s[1], argv, m1+o);
}
if (r) {
- regs[m1+o+1] = mrb_ary_new_from_values(mrb, argc-m1-o-m2, argv+m1+o);
+ rnum = argc-m1-o-m2;
+ regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
}
if (m2) {
if (argc-m2 > m1) {
- value_move(®s[m1+o+r+1], &argv[argc-m2], m2);
+ value_move(®s[m1+o+r+1], &argv[m1+o+rnum], m2);
}
}
if (argv0 == argv) {
regs[len+1] = *blk; /* move block */
}
@@ -1246,11 +1421,11 @@
}
JUMP;
}
CASE(OP_KARG) {
- /* A B C R(A) := kdict[Sym(B)]; if C kdict.rm(Sym(B)) */
+ /* 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 */
NEXT;
}
@@ -1261,11 +1436,11 @@
L_RETURN:
i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL);
/* fall through */
CASE(OP_RETURN) {
- /* A return R(A) */
+ /* A B return R(A) (B=normal,in-block return/break) */
if (mrb->exc) {
mrb_callinfo *ci;
int eidx;
L_RAISE:
@@ -1281,47 +1456,58 @@
ecall(mrb, --eidx);
}
while (ci[0].ridx == ci[-1].ridx) {
cipop(mrb);
ci = mrb->c->ci;
- mrb->c->stack = mrb->c->stbase + ci[1].stackidx;
+ mrb->c->stack = ci[1].stackent;
if (ci[1].acc == CI_ACC_SKIP && prev_jmp) {
mrb->jmp = prev_jmp;
- mrb_longjmp(mrb);
+ MRB_THROW(prev_jmp);
}
if (ci > mrb->c->cibase) {
while (eidx > ci[-1].eidx) {
ecall(mrb, --eidx);
}
}
else if (ci == mrb->c->cibase) {
if (ci->ridx == 0) {
- regs = mrb->c->stack = mrb->c->stbase;
- goto L_STOP;
+ if (mrb->c == mrb->root_c) {
+ regs = mrb->c->stack = mrb->c->stbase;
+ goto L_STOP;
+ }
+ else {
+ struct mrb_context *c = mrb->c;
+
+ mrb->c = c->prev;
+ c->prev = NULL;
+ goto L_RAISE;
+ }
}
break;
}
}
L_RESCUE:
- irep = ci->proc->body.irep;
+ if (ci->ridx == 0) goto L_STOP;
+ proc = ci->proc;
+ irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
- regs = mrb->c->stack = mrb->c->stbase + ci[1].stackidx;
+ regs = mrb->c->stack = ci[1].stackent;
pc = mrb->c->rescue[--ci->ridx];
}
else {
mrb_callinfo *ci = mrb->c->ci;
int acc, eidx = mrb->c->ci->eidx;
mrb_value v = regs[GETARG_A(i)];
switch (GETARG_B(i)) {
case OP_R_RETURN:
- // Fall through to OP_R_NORMAL otherwise
+ /* Fall through to OP_R_NORMAL otherwise */
if (proc->env && !MRB_PROC_STRICT_P(proc)) {
struct REnv *e = top_env(mrb, proc);
- if (e->cioff < 0) {
+ if (!MRB_ENV_STACK_SHARED_P(e)) {
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
ci = mrb->c->cibase + e->cioff;
if (ci == mrb->c->cibase) {
@@ -1336,11 +1522,11 @@
if (!mrb->c->prev) { /* toplevel return */
localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
goto L_RAISE;
}
if (mrb->c->prev->ci == mrb->c->prev->cibase) {
- mrb_value exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mrb_str_new(mrb, "double resume", 13));
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
/* automatic yield at the end */
mrb->c->status = MRB_FIBER_TERMINATED;
@@ -1348,15 +1534,30 @@
mrb->c->status = MRB_FIBER_RUNNING;
}
ci = mrb->c->ci;
break;
case OP_R_BREAK:
- if (proc->env->cioff < 0) {
+ if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
localjump_error(mrb, LOCALJUMP_ERROR_BREAK);
goto L_RAISE;
}
- ci = mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
+ /* break from fiber block */
+ if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) {
+ struct mrb_context *c = mrb->c;
+
+ mrb->c = c->prev;
+ c->prev = NULL;
+ }
+ ci = mrb->c->ci;
+ mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
+ while (ci > mrb->c->ci) {
+ if (ci[-1].acc == CI_ACC_SKIP) {
+ mrb->c->ci = ci;
+ break;
+ }
+ ci--;
+ }
break;
default:
/* cannot happen */
break;
}
@@ -1364,11 +1565,11 @@
ecall(mrb, --eidx);
}
cipop(mrb);
acc = ci->acc;
pc = ci->pc;
- regs = mrb->c->stack = mrb->c->stbase + ci->stackidx;
+ regs = mrb->c->stack = ci->stackent;
if (acc == CI_ACC_SKIP) {
mrb->jmp = prev_jmp;
return v;
}
DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid)));
@@ -1381,11 +1582,11 @@
}
JUMP;
}
CASE(OP_TAILCALL) {
- /* A B C return call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */
+ /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */
int a = GETARG_A(i);
int n = GETARG_C(i);
struct RProc *m;
struct RClass *c;
mrb_callinfo *ci;
@@ -1435,11 +1636,11 @@
syms = irep->syms;
if (ci->argc < 0) {
stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
}
else {
- stack_extend(mrb, irep->nregs, ci->argc+2);
+ stack_extend(mrb, irep->nregs, ci->argc+2);
}
regs = mrb->c->stack;
pc = irep->iseq;
}
JUMP;
@@ -1466,22 +1667,13 @@
}
regs[a] = stack[m1+r+m2];
NEXT;
}
-#define attr_i value.i
-#ifdef MRB_NAN_BOXING
-#define attr_f f
-#elif defined(MRB_WORD_BOXING)
-#define attr_f value.fp->f
-#else
-#define attr_f value.f
-#endif
-
#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff))
#define OP_MATH_BODY(op,v1,v2) do {\
- regs[a].v1 = regs[a].v1 op regs[a+1].v2;\
+ 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);
@@ -1493,49 +1685,44 @@
mrb_int x, y, z;
mrb_value *regs_a = regs + a;
x = mrb_fixnum(regs_a[0]);
y = mrb_fixnum(regs_a[1]);
- z = x + y;
-#ifdef MRB_WORD_BOXING
- z = (z << MRB_FIXNUM_SHIFT) / (1 << MRB_FIXNUM_SHIFT);
-#endif
- if ((x < 0) != (z < 0) && ((x < 0) ^ (y < 0)) == 0) {
- /* integer overflow */
- SET_FLT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y);
+ if (mrb_int_add_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y);
break;
}
SET_INT_VALUE(regs[a], z);
}
break;
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x + y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y);
}
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_FLT_VALUE(mrb, regs[a], x + y);
+ SET_FLOAT_VALUE(mrb, regs[a], x + y);
}
#else
- OP_MATH_BODY(+,attr_f,attr_i);
+ OP_MATH_BODY(+,mrb_float,mrb_fixnum);
#endif
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_FLT_VALUE(mrb, regs[a], x + y);
+ SET_FLOAT_VALUE(mrb, regs[a], x + y);
}
#else
- OP_MATH_BODY(+,attr_f,attr_f);
+ OP_MATH_BODY(+,mrb_float,mrb_float);
#endif
break;
case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
break;
@@ -1556,49 +1743,44 @@
{
mrb_int x, y, z;
x = mrb_fixnum(regs[a]);
y = mrb_fixnum(regs[a+1]);
- z = x - y;
-#ifdef MRB_WORD_BOXING
- z = (z << MRB_FIXNUM_SHIFT) / (1 << MRB_FIXNUM_SHIFT);
-#endif
- if (((x < 0) ^ (y < 0)) != 0 && (x < 0) != (z < 0)) {
- /* integer overflow */
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y);
+ if (mrb_int_sub_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y);
break;
}
SET_INT_VALUE(regs[a], z);
}
break;
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x - y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y);
}
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_FLT_VALUE(mrb, regs[a], x - y);
+ SET_FLOAT_VALUE(mrb, regs[a], x - y);
}
#else
- OP_MATH_BODY(-,attr_f,attr_i);
+ OP_MATH_BODY(-,mrb_float,mrb_fixnum);
#endif
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_FLT_VALUE(mrb, regs[a], x - y);
+ SET_FLOAT_VALUE(mrb, regs[a], x - y);
}
#else
- OP_MATH_BODY(-,attr_f,attr_f);
+ OP_MATH_BODY(-,mrb_float,mrb_float);
#endif
break;
default:
goto L_SEND;
}
@@ -1611,53 +1793,58 @@
/* 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 z;
- x = mrb_fixnum(regs[a]);
- y = mrb_fixnum(regs[a+1]);
- z = x * y;
-#ifdef MRB_WORD_BOXING
- z = (z << MRB_FIXNUM_SHIFT) / (1 << MRB_FIXNUM_SHIFT);
-#endif
- if (x != 0 && z/x != y) {
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y);
+ z = mrb_fixnum_mul(mrb, regs[a], regs[a+1]);
+
+ switch (mrb_type(z)) {
+ case MRB_TT_FIXNUM:
+ {
+ SET_INT_VALUE(regs[a], mrb_fixnum(z));
+ }
+ break;
+ case MRB_TT_FLOAT:
+ {
+ SET_FLOAT_VALUE(mrb, regs[a], mrb_float(z));
+ }
+ break;
+ default:
+ /* cannot happen */
+ break;
}
- else {
- SET_INT_VALUE(regs[a], z);
- }
}
break;
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x * y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y);
}
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_FLT_VALUE(mrb, regs[a], x * y);
+ SET_FLOAT_VALUE(mrb, regs[a], x * y);
}
#else
- OP_MATH_BODY(*,attr_f,attr_i);
+ OP_MATH_BODY(*,mrb_float,mrb_fixnum);
#endif
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_FLT_VALUE(mrb, regs[a], x * y);
+ SET_FLOAT_VALUE(mrb, regs[a], x * y);
}
#else
- OP_MATH_BODY(*,attr_f,attr_f);
+ OP_MATH_BODY(*,mrb_float,mrb_float);
#endif
break;
default:
goto L_SEND;
}
@@ -1672,45 +1859,50 @@
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_int y = mrb_fixnum(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x / (mrb_float)y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / (mrb_float)y);
}
break;
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
{
mrb_int x = mrb_fixnum(regs[a]);
mrb_float y = mrb_float(regs[a+1]);
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x / y);
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / y);
}
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_FLT_VALUE(mrb, regs[a], x / y);
+ SET_FLOAT_VALUE(mrb, regs[a], x / y);
}
#else
- OP_MATH_BODY(/,attr_f,attr_i);
+ OP_MATH_BODY(/,mrb_float,mrb_fixnum);
#endif
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_FLT_VALUE(mrb, regs[a], x / y);
+ SET_FLOAT_VALUE(mrb, regs[a], x / y);
}
#else
- OP_MATH_BODY(/,attr_f,attr_f);
+ OP_MATH_BODY(/,mrb_float,mrb_float);
#endif
break;
default:
goto L_SEND;
}
+#ifdef MRB_NAN_BOXING
+ if (isnan(mrb_float(regs[a]))) {
+ regs[a] = mrb_float_value(mrb, mrb_float(regs[a]));
+ }
+#endif
NEXT;
}
CASE(OP_ADDI) {
/* A B C R(A) := R(A)+C (Syms[B]=:+)*/
@@ -1718,30 +1910,29 @@
/* need to check if + is overridden */
switch (mrb_type(regs[a])) {
case MRB_TT_FIXNUM:
{
- mrb_int x = regs[a].attr_i;
+ mrb_int x = mrb_fixnum(regs[a]);
mrb_int y = GETARG_C(i);
- mrb_int z = x + y;
+ mrb_int z;
- if (((x < 0) ^ (y < 0)) == 0 && (x < 0) != (z < 0)) {
- /* integer overflow */
- SET_FLT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y);
+ if (mrb_int_add_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y);
break;
}
- regs[a].attr_i = z;
+ SET_INT_VALUE(regs[a], z);
}
break;
case MRB_TT_FLOAT:
#ifdef MRB_WORD_BOXING
{
mrb_float x = mrb_float(regs[a]);
- SET_FLT_VALUE(mrb, regs[a], x + GETARG_C(i));
+ SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i));
}
#else
- regs[a].attr_f += GETARG_C(i);
+ mrb_float(regs[a]) += GETARG_C(i);
#endif
break;
default:
SET_INT_VALUE(regs[a+1], GETARG_C(i));
i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
@@ -1757,73 +1948,71 @@
/* need to check if + is overridden */
switch (mrb_type(regs_a[0])) {
case MRB_TT_FIXNUM:
{
- mrb_int x = regs_a[0].attr_i;
+ mrb_int x = mrb_fixnum(regs_a[0]);
mrb_int y = GETARG_C(i);
- mrb_int z = x - y;
+ mrb_int z;
- if ((x < 0) != (z < 0) && ((x < 0) ^ (y < 0)) != 0) {
- /* integer overflow */
- SET_FLT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y);
+ if (mrb_int_sub_overflow(x, y, &z)) {
+ SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y);
}
else {
- regs_a[0].attr_i = z;
+ SET_INT_VALUE(regs_a[0], z);
}
}
break;
case MRB_TT_FLOAT:
#ifdef MRB_WORD_BOXING
{
mrb_float x = mrb_float(regs[a]);
- SET_FLT_VALUE(mrb, regs[a], x - GETARG_C(i));
+ SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i));
}
#else
- regs_a[0].attr_f -= GETARG_C(i);
+ mrb_float(regs_a[0]) -= GETARG_C(i);
#endif
break;
default:
SET_INT_VALUE(regs_a[1], GETARG_C(i));
i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
goto L_SEND;
}
NEXT;
}
-#define OP_CMP_BODY(op,v1,v2) do {\
- if (regs[a].v1 op regs[a+1].v2) {\
- SET_TRUE_VALUE(regs[a]);\
- }\
- else {\
- SET_FALSE_VALUE(regs[a]);\
- }\
-} while(0)
+#define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1]))
#define OP_CMP(op) do {\
- int a = GETARG_A(i);\
+ int result;\
/* need to check if - is overridden */\
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\
- OP_CMP_BODY(op,attr_i,attr_i);\
+ result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\
break;\
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
- OP_CMP_BODY(op,attr_i,attr_f);\
+ result = OP_CMP_BODY(op,mrb_fixnum,mrb_float);\
break;\
case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\
- OP_CMP_BODY(op,attr_f,attr_i);\
+ result = OP_CMP_BODY(op,mrb_float,mrb_fixnum);\
break;\
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
- OP_CMP_BODY(op,attr_f,attr_f);\
+ result = OP_CMP_BODY(op,mrb_float,mrb_float);\
break;\
default:\
goto L_SEND;\
}\
+ if (result) {\
+ SET_TRUE_VALUE(regs[a]);\
+ }\
+ else {\
+ SET_FALSE_VALUE(regs[a]);\
+ }\
} while(0)
CASE(OP_EQ) {
- /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:==,C=1)*/
+ /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/
int a = GETARG_A(i);
if (mrb_obj_eq(mrb, regs[a], regs[a+1])) {
SET_TRUE_VALUE(regs[a]);
}
else {
@@ -1832,28 +2021,32 @@
NEXT;
}
CASE(OP_LT) {
/* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
+ int a = GETARG_A(i);
OP_CMP(<);
NEXT;
}
CASE(OP_LE) {
/* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/
+ int a = GETARG_A(i);
OP_CMP(<=);
NEXT;
}
CASE(OP_GT) {
- /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
+ /* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1)*/
+ int a = GETARG_A(i);
OP_CMP(>);
NEXT;
}
CASE(OP_GE) {
- /* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/
+ /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/
+ int a = GETARG_A(i);
OP_CMP(>=);
NEXT;
}
CASE(OP_ARRAY) {
@@ -1918,26 +2111,26 @@
}
}
else {
struct RArray *ary = mrb_ary_ptr(v);
int len = ary->len;
- int i;
+ int idx;
if (len > pre + post) {
regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre);
while (post--) {
regs[a++] = ary->ptr[len-post-1];
}
}
else {
regs[a++] = mrb_ary_new_capa(mrb, 0);
- for (i=0; i+pre<len; i++) {
- regs[a+i] = ary->ptr[pre+i];
+ for (idx=0; idx+pre<len; idx++) {
+ regs[a+idx] = ary->ptr[pre+idx];
}
- while (i < post) {
- SET_NIL_VALUE(regs[a+i]);
- i++;
+ while (idx < post) {
+ SET_NIL_VALUE(regs[a+idx]);
+ idx++;
}
}
}
ARENA_RESTORE(mrb, ai);
NEXT;
@@ -1980,10 +2173,19 @@
if (c & OP_L_CAPTURE) {
p = mrb_closure_new(mrb, irep->reps[GETARG_b(i)]);
}
else {
p = mrb_proc_new(mrb, irep->reps[GETARG_b(i)]);
+ if (c & OP_L_METHOD) {
+ if (p->target_class->tt == MRB_TT_SCLASS) {
+ mrb_value klass;
+ klass = mrb_obj_iv_get(mrb,
+ (struct RObject *)p->target_class,
+ mrb_intern_lit(mrb, "__attached__"));
+ p->target_class = mrb_class_ptr(klass);
+ }
+ }
}
if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
regs[GETARG_A(i)] = mrb_obj_value(p);
ARENA_RESTORE(mrb, ai);
NEXT;
@@ -1994,11 +2196,11 @@
regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class);
NEXT;
}
CASE(OP_CLASS) {
- /* A B R(A) := newclass(R(A),Sym(B),R(A+1)) */
+ /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */
struct RClass *c = 0;
int a = GETARG_A(i);
mrb_value base, super;
mrb_sym id = syms[GETARG_B(i)];
@@ -2012,11 +2214,11 @@
ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_MODULE) {
- /* A B R(A) := newmodule(R(A),Sym(B)) */
+ /* A B R(A) := newmodule(R(A),Syms(B)) */
struct RClass *c = 0;
int a = GETARG_A(i);
mrb_value base;
mrb_sym id = syms[GETARG_B(i)];
@@ -2040,11 +2242,11 @@
/* prepare stack */
ci = cipush(mrb);
ci->pc = pc + 1;
ci->acc = a;
ci->mid = 0;
- ci->stackidx = mrb->c->stack - mrb->c->stbase;
+ ci->stackent = mrb->c->stack;
ci->argc = 0;
ci->target_class = mrb_class_ptr(recv);
/* prepare stack */
mrb->c->stack += a;
@@ -2052,15 +2254,16 @@
p = mrb_proc_new(mrb, irep->reps[GETARG_Bx(i)]);
p->target_class = ci->target_class;
ci->proc = p;
if (MRB_PROC_CFUNC_P(p)) {
+ ci->nregs = 0;
mrb->c->stack[0] = p->body.func(mrb, recv);
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc) goto L_RAISE;
/* pop stackpos */
- regs = mrb->c->stack = mrb->c->stbase + mrb->c->ci->stackidx;
+ regs = mrb->c->stack = mrb->c->ci->stackent;
cipop(mrb);
NEXT;
}
else {
irep = p->body.irep;
@@ -2073,11 +2276,11 @@
JUMP;
}
}
CASE(OP_METHOD) {
- /* A B R(A).newmethod(Sym(B),R(A+1)) */
+ /* A B R(A).newmethod(Syms(B),R(A+1)) */
int a = GETARG_A(i);
struct RClass *c = mrb_class_ptr(regs[a]);
mrb_define_method_vm(mrb, c, syms[GETARG_B(i)], regs[a+1]);
ARENA_RESTORE(mrb, ai);
@@ -2090,14 +2293,13 @@
ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_TCLASS) {
- /* A B R(A) := target_class */
+ /* A R(A) := target_class */
if (!mrb->c->ci->target_class) {
- static const char msg[] = "no target class or module";
- mrb_value exc = mrb_exc_new(mrb, E_TYPE_ERROR, msg, sizeof(msg) - 1);
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class);
NEXT;
@@ -2110,27 +2312,31 @@
ARENA_RESTORE(mrb, ai);
NEXT;
}
CASE(OP_DEBUG) {
- /* A debug print R(A),R(B),R(C) */
+ /* A B C debug print R(A),R(B),R(C) */
+#ifdef ENABLE_DEBUG
+ mrb->debug_op_hook(mrb, irep, pc, regs);
+#else
#ifdef ENABLE_STDIO
printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
#else
abort();
#endif
+#endif
NEXT;
}
CASE(OP_STOP) {
/* stop VM */
L_STOP:
{
- int n = mrb->c->ci->eidx;
-
- while (n--) {
- ecall(mrb, n);
+ int eidx_stop = mrb->c->ci == mrb->c->cibase ? 0 : mrb->c->ci[-1].eidx;
+ int eidx = mrb->c->ci->eidx;
+ while (eidx > eidx_stop) {
+ ecall(mrb, --eidx);
}
}
ERR_PC_CLR(mrb);
mrb->jmp = prev_jmp;
if (mrb->exc) {
@@ -2153,18 +2359,44 @@
mrb->exc = mrb_obj_ptr(exc);
goto L_RAISE;
}
}
END_DISPATCH;
+
+ }
+ MRB_CATCH(&c_jmp) {
+ exc_catched = TRUE;
+ goto RETRY_TRY_BLOCK;
+ }
+ MRB_END_EXC(&c_jmp);
}
-mrb_value
+MRB_API mrb_value
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
- return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+ return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
}
-void
-mrb_longjmp(mrb_state *mrb)
+MRB_API mrb_value
+mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep)
{
- longjmp(*(jmp_buf*)mrb->jmp, 1);
+ mrb_callinfo *ci;
+ mrb_value v;
+
+ if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) {
+ return mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
+ }
+ ci = cipush(mrb);
+ ci->nregs = 1; /* protect the receiver */
+ ci->acc = CI_ACC_SKIP;
+ ci->target_class = mrb->object_class;
+ v = mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
+ cipop(mrb);
+
+ return v;
+}
+
+MRB_API mrb_value
+mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
+{
+ return mrb_toplevel_run_keep(mrb, proc, 0);
}