summaryrefslogtreecommitdiffhomepage
path: root/src/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c80
1 files changed, 58 insertions, 22 deletions
diff --git a/src/vm.c b/src/vm.c
index ce77f5b05..953863a0b 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -38,6 +38,16 @@
#define STACK_INIT_SIZE 128
#define CALLINFO_INIT_SIZE 32
+static inline void
+stack_copy(mrb_value *dst, const mrb_value *src, size_t size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ dst[i] = src[i];
+ }
+}
+
static void
stack_init(mrb_state *mrb)
{
@@ -90,15 +100,16 @@ stack_extend(mrb_state *mrb, int room, int keep)
envadjust(mrb, oldbase, mrb->stbase);
}
if (room > keep) {
-#ifndef MRB_NAN_BOXING
- memset(mrb->stack+keep, 0, sizeof(mrb_value) * (room-keep));
-#else
int i;
for (i=keep; i<room; i++) {
+#ifndef MRB_NAN_BOXING
+ static const mrb_value mrb_value_zero = { { 0 } };
+ mrb->stack[i] = mrb_value_zero;
+#else
SET_NIL_VALUE(mrb->stack[i]);
- }
#endif
+ }
}
}
@@ -170,7 +181,7 @@ cipop(mrb_state *mrb)
mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
e->cioff = -1;
- memcpy(p, e->stack, sizeof(mrb_value)*len);
+ stack_copy(p, e->stack, len);
e->stack = p;
}
@@ -226,7 +237,7 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, int argc, ...)
mrb_value argv[MRB_FUNCALL_ARGC_MAX];
if (argc > MRB_FUNCALL_ARGC_MAX) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=%d)", MRB_FUNCALL_ARGC_MAX);
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=%d)", MRB_FUNCALL_ARGC_MAX);
}
va_start(ap, argc);
@@ -267,7 +278,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mr
}
n = mrb->ci->nregs;
if (argc < 0) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%d)", argc);
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%d)", argc);
}
c = mrb_class(mrb, self);
p = mrb_method_search_vm(mrb, &c, mid);
@@ -296,10 +307,10 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mr
mrb->stack[0] = self;
if (undef) {
mrb->stack[1] = mrb_symbol_value(undef);
- memcpy(mrb->stack+2, argv, sizeof(mrb_value)*(argc-1));
+ stack_copy(mrb->stack+2, argv, argc-1);
}
else if (argc > 0) {
- memcpy(mrb->stack+1, argv, sizeof(mrb_value)*argc);
+ stack_copy(mrb->stack+1, argv, argc);
}
mrb->stack[argc+1] = blk;
@@ -351,7 +362,7 @@ mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_v
stack_extend(mrb, ci->nregs, 0);
mrb->stack[0] = self;
if (argc > 0) {
- memcpy(mrb->stack+1, argv, sizeof(mrb_value)*argc);
+ stack_copy(mrb->stack+1, argv, argc);
}
mrb->stack[argc+1] = mrb_nil_value();
@@ -455,7 +466,6 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
int ai = mrb->arena_idx;
jmp_buf *prev_jmp = (jmp_buf *)mrb->jmp;
jmp_buf c_jmp;
- ptrdiff_t ciidx = mrb->ci - mrb->cibase;
#ifdef DIRECT_THREADED
static void *optable[] = {
@@ -990,12 +1000,12 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
}
regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
rest = mrb_ary_ptr(regs[a]);
- memcpy(rest->ptr, stack, sizeof(mrb_value)*m1);
+ stack_copy(rest->ptr, stack, m1);
if (len > 0) {
- memcpy(rest->ptr+m1, pp, sizeof(mrb_value)*len);
+ stack_copy(rest->ptr+m1, pp, len);
}
if (m2 > 0) {
- memcpy(rest->ptr+m1+len, stack+m1+1, sizeof(mrb_value)*m2);
+ stack_copy(rest->ptr+m1+len, stack+m1+1, m2);
}
rest->len = m1+len+m2;
}
@@ -1096,14 +1106,10 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
ci = mrb->ci;
eidx = mrb->ci->eidx;
if (ci == mrb->cibase) goto L_STOP;
- if (ciidx == ci - mrb->cibase){
- mrb->jmp = prev_jmp;
- longjmp(*(jmp_buf*)mrb->jmp, 1);
- }
while (ci[0].ridx == ci[-1].ridx) {
cipop(mrb);
ci = mrb->ci;
- if (ci->acc < 0) {
+ if (ci[1].acc < 0 && prev_jmp) {
mrb->jmp = prev_jmp;
longjmp(*(jmp_buf*)mrb->jmp, 1);
}
@@ -1131,6 +1137,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
switch (GETARG_B(i)) {
case OP_R_NORMAL:
+ NORMAL_RETURN:
if (ci == mrb->cibase) {
localjump_error(mrb, "return");
goto L_RAISE;
@@ -1145,6 +1152,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
ci = mrb->ci = mrb->cibase + proc->env->cioff + 1;
break;
case OP_R_RETURN:
+ if (!proc->env) goto NORMAL_RETURN;
if (proc->env->cioff < 0) {
localjump_error(mrb, "return");
goto L_RAISE;
@@ -1436,7 +1444,18 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
/* need to check if + is overridden */
switch (mrb_type(regs[a])) {
case MRB_TT_FIXNUM:
- regs[a].attr_i += GETARG_C(i);
+ {
+ mrb_int x = regs[a].attr_i;
+ mrb_int y = GETARG_C(i);
+ mrb_int z = x + y;
+
+ if (((x < 0) ^ (y < 0)) == 0 && (x < 0) != (z < 0)) {
+ /* integer overflow */
+ SET_FLT_VALUE(regs[a], (mrb_float)x + (mrb_float)y);
+ break;
+ }
+ regs[a].attr_i = z;
+ }
break;
case MRB_TT_FLOAT:
regs[a].attr_f += GETARG_C(i);
@@ -1456,7 +1475,18 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
/* need to check if + is overridden */
switch (mrb_type(regs[a])) {
case MRB_TT_FIXNUM:
- regs[a].attr_i -= GETARG_C(i);
+ {
+ mrb_int x = regs[a].attr_i;
+ mrb_int y = GETARG_C(i);
+ mrb_int z = x - y;
+
+ if (((x < 0) ^ (y < 0)) == 0 && (x < 0) != (z < 0)) {
+ /* integer overflow */
+ SET_FLT_VALUE(regs[a], (mrb_float)x - (mrb_float)y);
+ break;
+ }
+ regs[a].attr_i = z;
+ }
break;
case MRB_TT_FLOAT:
regs[a].attr_f -= GETARG_C(i);
@@ -1820,8 +1850,14 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_ERR) {
/* Bx raise RuntimeError with message Lit(Bx) */
mrb_value msg = pool[GETARG_Bx(i)];
- mrb_value exc = mrb_exc_new3(mrb, E_RUNTIME_ERROR, msg);
+ mrb_value exc;
+ if (GETARG_A(i) == 0) {
+ exc = mrb_exc_new3(mrb, E_RUNTIME_ERROR, msg);
+ }
+ else {
+ exc = mrb_exc_new3(mrb, E_LOCALJUMP_ERROR, msg);
+ }
mrb->exc = (struct RObject*)mrb_object(exc);
goto L_RAISE;
}