Index: EcnlProtoTool/trunk/mruby-1.3.0/src/vm.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/src/vm.c	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/src/vm.c	(revision 331)
@@ -8,20 +8,20 @@
 #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 "mruby/error.h"
-#include "mruby/opcode.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 <mruby/error.h>
+#include <mruby/opcode.h>
 #include "value_array.h"
-#include "mruby/throw.h"
-
-#ifdef MRB_DISABLE_STDIO
+#include <mruby/throw.h>
+
+#ifndef MRB_DISABLE_STDIO
 #if defined(__cplusplus)
 extern "C" {
@@ -36,7 +36,20 @@
 #define CALLINFO_INIT_SIZE 32
 
+#ifndef ENSURE_STACK_INIT_SIZE
+#define ENSURE_STACK_INIT_SIZE 16
+#endif
+
+#ifndef RESCUE_STACK_INIT_SIZE
+#define RESCUE_STACK_INIT_SIZE 16
+#endif
+
 /* Define amount of linear stack growth. */
 #ifndef MRB_STACK_GROWTH
 #define MRB_STACK_GROWTH 128
+#endif
+
+/* Maximum mrb_funcall() depth. Should be set lower on memory constrained systems. */
+#ifndef MRB_FUNCALL_DEPTH_MAX
+#define MRB_FUNCALL_DEPTH_MAX 512
 #endif
 
@@ -54,4 +67,8 @@
 
 #define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai)
+
+#define CALL_MAXARGS 127
+
+void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
 
 static inline void
@@ -99,5 +116,5 @@
 
 static inline void
-envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase)
+envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase, size_t size)
 {
   mrb_callinfo *ci = mrb->c->cibase;
@@ -106,5 +123,8 @@
   while (ci <= mrb->c->ci) {
     struct REnv *e = ci->env;
-    if (e && MRB_ENV_STACK_SHARED_P(e)) {
+    mrb_value *st;
+
+    if (e && MRB_ENV_STACK_SHARED_P(e) &&
+        (st = e->stack) && oldbase <= st && st < oldbase+size) {
       ptrdiff_t off = e->stack - oldbase;
 
@@ -116,22 +136,16 @@
 }
 
-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, int keep)
+stack_extend_alloc(mrb_state *mrb, int room)
 {
   mrb_value *oldbase = mrb->c->stbase;
-  int size = mrb->c->stend - mrb->c->stbase;
-  int off = mrb->c->stack - mrb->c->stbase;
-
+  mrb_value *newstack;
+  size_t oldsize = mrb->c->stend - mrb->c->stbase;
+  size_t size = oldsize;
+  size_t off = mrb->c->stack - mrb->c->stbase;
+
+  if (off > size) size = off;
 #ifdef MRB_STACK_EXTEND_DOUBLING
   if (room <= size)
@@ -149,24 +163,27 @@
 #endif
 
-  mrb->c->stbase = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
+  newstack = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
+  if (newstack == NULL) {
+    mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
+  }
+  stack_clear(&(newstack[oldsize]), size - oldsize);
+  envadjust(mrb, oldbase, newstack, size);
+  mrb->c->stbase = newstack;
   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) {
-    init_new_stack_space(mrb, room, keep);
-    mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")");
+    mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
   }
 }
 
 static inline void
-stack_extend(mrb_state *mrb, int room, int keep)
+stack_extend(mrb_state *mrb, int room)
 {
   if (mrb->c->stack + room >= mrb->c->stend) {
-    stack_extend_alloc(mrb, room, keep);
-  }
-  init_new_stack_space(mrb, room, keep);
+    stack_extend_alloc(mrb, room);
+  }
 }
 
@@ -188,6 +205,6 @@
   int cioff = e->cioff;
 
-  if (MRB_ENV_STACK_SHARED_P(e) && mrb->c->cibase[cioff].proc &&
-      MRB_PROC_STRICT_P(mrb->c->cibase[cioff].proc)) {
+  if (MRB_ENV_STACK_SHARED_P(e) && e->cxt.c->cibase[cioff].proc &&
+      MRB_PROC_STRICT_P(e->cxt.c->cibase[cioff].proc)) {
     return TRUE;
   }
@@ -210,4 +227,5 @@
 #define CI_ACC_SKIP    -1
 #define CI_ACC_DIRECT  -2
+#define CI_ACC_RESUMED -3
 
 static mrb_callinfo*
@@ -217,5 +235,4 @@
   mrb_callinfo *ci = c->ci;
 
-  int eidx = ci->eidx;
   int ridx = ci->ridx;
 
@@ -228,5 +245,5 @@
   }
   ci = ++c->ci;
-  ci->eidx = eidx;
+  ci->epos = mrb->c->eidx;
   ci->ridx = ridx;
   ci->env = 0;
@@ -234,6 +251,31 @@
   ci->err = 0;
   ci->proc = 0;
+  ci->acc = 0;
 
   return ci;
+}
+
+MRB_API void
+mrb_env_unshare(mrb_state *mrb, struct REnv *e)
+{
+  size_t len = (size_t)MRB_ENV_STACK_LEN(e);
+  ptrdiff_t cioff = e->cioff;
+  mrb_value *p;
+
+  if (!MRB_ENV_STACK_SHARED_P(e)) return;
+  if (e->cxt.c != mrb->c) return;
+  if (e->cioff == 0 && e->cxt.c == mrb->root_c) return;
+  MRB_ENV_UNSHARE_STACK(e);
+  if (!e->c) {
+    /* save block argument position (negated) */
+    e->cioff = -e->cxt.c->cibase[cioff].argc-1;
+  }
+  e->cxt.mid = e->cxt.c->cibase[cioff].mid;
+  p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
+  if (len > 0) {
+    stack_copy(p, e->stack, len);
+  }
+  e->stack = p;
+  mrb_write_barrier(mrb, (struct RBasic *)e);
 }
 
@@ -242,20 +284,14 @@
 {
   struct mrb_context *c = mrb->c;
-
-  if (c->ci->env) {
-    struct REnv *e = c->ci->env;
-    size_t len = (size_t)MRB_ENV_STACK_LEN(e);
-    mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*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);
-  }
+  struct REnv *env = c->ci->env;
 
   c->ci--;
-}
+
+  if (env) {
+    mrb_env_unshare(mrb, env);
+  }
+}
+
+void mrb_exc_set(mrb_state *mrb, mrb_value exc);
 
 static void
@@ -263,13 +299,18 @@
 {
   struct RProc *p;
-  mrb_callinfo *ci;
+  mrb_callinfo *ci = mrb->c->ci;
   mrb_value *self = mrb->c->stack;
   struct RObject *exc;
+  ptrdiff_t cioff;
+  int ai = mrb_gc_arena_save(mrb);
 
   if (i<0) return;
+  if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+    mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
+  }
   p = mrb->c->ensure[i];
   if (!p) return;
-  if (mrb->c->ci->eidx > i)
-    mrb->c->ci->eidx = i;
+  mrb->c->ensure[i] = NULL;
+  cioff = ci - mrb->c->cibase;
   ci = cipush(mrb);
   ci->stackent = mrb->c->stack;
@@ -282,7 +323,11 @@
   mrb->c->stack = mrb->c->stack + ci[-1].nregs;
   exc = mrb->exc; mrb->exc = 0;
+  if (exc) {
+    mrb_gc_protect(mrb, mrb_obj_value(exc));
+  }
   mrb_run(mrb, p, *self);
-  mrb->c->ensure[i] = NULL;
+  mrb->c->ci = mrb->c->cibase + cioff;
   if (!mrb->exc) mrb->exc = exc;
+  mrb_gc_arena_restore(mrb, ai);
 }
 
@@ -335,9 +380,9 @@
     }
     MRB_END_EXC(&c_jmp);
+    mrb->jmp = 0;
   }
   else {
     struct RProc *p;
     struct RClass *c;
-    mrb_sym undef = 0;
     mrb_callinfo *ci;
     int n;
@@ -354,8 +399,17 @@
     p = mrb_method_search_vm(mrb, &c, mid);
     if (!p) {
-      undef = mid;
-      mid = mrb_intern_lit(mrb, "method_missing");
-      p = mrb_method_search_vm(mrb, &c, mid);
-      n++; argc++;
+      mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+      mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
+      p = mrb_method_search_vm(mrb, &c, missing);
+      if (!p) {
+        mrb_method_missing(mrb, mid, self, args);
+      }
+      mrb_ary_unshift(mrb, args, mrb_symbol_value(mid));
+      stack_extend(mrb, n+2);
+      mrb->c->stack[n+1] = args;
+      argc = -1;
+    }
+    if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+      mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
     }
     ci = cipush(mrb);
@@ -371,9 +425,17 @@
     if (MRB_PROC_CFUNC_P(p)) {
       ci->nregs = argc + 2;
-      stack_extend(mrb, ci->nregs, 0);
+      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);
+      mrb->c->stack[1] = args;
+      ci->argc = -1;
+      argc = 1;
     }
     else {
-      ci->nregs = p->body.irep->nregs + n;
-      stack_extend(mrb, ci->nregs, argc+2);
+      if (argc < 0) argc = 1;
+      ci->nregs = p->body.irep->nregs + argc;
+      stack_extend(mrb, ci->nregs);
     }
     if (voff >= 0) {
@@ -381,11 +443,5 @@
     }
     mrb->c->stack[0] = self;
-    if (undef) {
-      mrb->c->stack[1] = mrb_symbol_value(undef);
-      if (argc > 1) {
-        stack_copy(mrb->c->stack+2, argv, argc-1);
-      }
-    }
-    else if (argc > 0) {
+    if (ci->argc > 0) {
       stack_copy(mrb->c->stack+1, argv, argc);
     }
@@ -414,4 +470,33 @@
 {
   return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
+}
+
+mrb_value
+mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
+{
+  mrb_callinfo *ci = mrb->c->ci;
+
+  mrb->c->stack[0] = self;
+  ci->proc = p;
+  ci->target_class = p->target_class;
+  if (MRB_PROC_CFUNC_P(p)) {
+    return p->body.func(mrb, self);
+  }
+  if (ci->argc < 0) {
+    stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs);
+  }
+  else {
+    stack_extend(mrb, p->body.irep->nregs);
+  }
+
+  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;
 }
 
@@ -446,4 +531,9 @@
 
   mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);
+  ci = mrb->c->ci;
+  if (ci->acc < 0) {
+  funcall:
+    return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
+  }
 
   c = mrb_class(mrb, self);
@@ -451,11 +541,9 @@
 
   if (!p) {                     /* call method_mising */
-    return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
-  }
-
-  ci = mrb->c->ci;
+    goto funcall;
+  }
+
   ci->mid = name;
   ci->target_class = c;
-  ci->proc = p;
   regs = mrb->c->stack+1;
   /* remove first symbol from arguments */
@@ -470,24 +558,5 @@
   }
 
-  if (MRB_PROC_CFUNC_P(p)) {
-    return p->body.func(mrb, self);
-  }
-
-  if (ci->argc < 0) {
-    stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
-  }
-  else {
-    stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
-  }
-
-  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;
+  return mrb_exec_irep(mrb, self, p);
 }
 
@@ -497,4 +566,5 @@
   struct RProc *p;
   mrb_callinfo *ci;
+  mrb_int max = 3;
 
   if (mrb_nil_p(blk)) {
@@ -503,13 +573,25 @@
   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;
+    return mrb_yield_cont(mrb, blk, self, 1, &self);
   }
   ci->target_class = c;
   p = mrb_proc_ptr(blk);
   ci->proc = p;
+  ci->argc = 1;
+  ci->mid = ci[-1].mid;
   if (MRB_PROC_CFUNC_P(p)) {
+    stack_extend(mrb, 3);
+    mrb->c->stack[0] = self;
+    mrb->c->stack[1] = self;
+    mrb->c->stack[2] = mrb_nil_value();
     return p->body.func(mrb, self);
   }
   ci->nregs = p->body.irep->nregs;
+  if (max < ci->nregs) max = ci->nregs;
+  stack_extend(mrb, max);
+  mrb->c->stack[0] = self;
+  mrb->c->stack[1] = self;
+  mrb->c->stack[2] = mrb_nil_value();
   ci = cipush(mrb);
   ci->nregs = 0;
@@ -600,4 +682,7 @@
     mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
   }
+  if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+    mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
+  }
   p = mrb_proc_ptr(b);
   ci = cipush(mrb);
@@ -611,9 +696,9 @@
   if (MRB_PROC_CFUNC_P(p)) {
     ci->nregs = argc + 2;
-    stack_extend(mrb, ci->nregs, 0);
+    stack_extend(mrb, ci->nregs);
   }
   else {
     ci->nregs = p->body.irep->nregs;
-    stack_extend(mrb, ci->nregs, argc+2);
+    stack_extend(mrb, ci->nregs);
   }
 
@@ -627,9 +712,11 @@
     val = p->body.func(mrb, self);
     mrb->c->stack = mrb->c->ci->stackent;
-    cipop(mrb);
   }
   else {
+    int cioff = mrb->c->ci - mrb->c->cibase;
     val = mrb_run(mrb, p, self);
-  }
+    mrb->c->ci = mrb->c->cibase + cioff;
+  }
+  cipop(mrb);
   return val;
 }
@@ -649,4 +736,40 @@
 
   return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
+}
+
+mrb_value
+mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv)
+{
+  struct RProc *p;
+  mrb_callinfo *ci;
+
+  if (mrb_nil_p(b)) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+  }
+  if (mrb_type(b) != MRB_TT_PROC) {
+    mrb_raise(mrb, E_TYPE_ERROR, "not a block");
+  }
+
+  p = mrb_proc_ptr(b);
+  ci = mrb->c->ci;
+
+  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;
+  return mrb_exec_irep(mrb, self, p);
+}
+
+static struct RBreak*
+break_new(mrb_state *mrb, struct RProc *p, mrb_value val)
+{
+  struct RBreak *brk;
+
+  brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL);
+  brk->iv = NULL;
+  brk->proc = p;
+  brk->val = val;
+
+  return brk;
 }
 
@@ -670,5 +793,5 @@
   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);
+  mrb_exc_set(mrb, exc);
 }
 
@@ -678,16 +801,23 @@
   mrb_value exc;
   mrb_value str;
-
+  mrb_int argc = mrb->c->ci->argc;
+
+  if (argc < 0) {
+    mrb_value args = mrb->c->stack[1];
+    if (mrb_array_p(args)) {
+      argc = RARRAY_LEN(args);
+    }
+  }
   if (mrb->c->ci->mid) {
     str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)",
                   mrb_sym2str(mrb, mrb->c->ci->mid),
-                  mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
+                  mrb_fixnum_value(argc), mrb_fixnum_value(num));
   }
   else {
     str = mrb_format(mrb, "wrong number of arguments (%S for %S)",
-                  mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
+                     mrb_fixnum_value(argc), mrb_fixnum_value(num));
   }
   exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
-  mrb->exc = mrb_obj_ptr(exc);
+  mrb_exc_set(mrb, exc);
 }
 
@@ -700,4 +830,11 @@
 #endif
 
+#ifdef MRB_BYTECODE_DECODE_OPTION
+#define BYTECODE_DECODER(x) ((mrb)->bytecode_decoder)?(mrb)->bytecode_decoder((mrb), (x)):(x)
+#else
+#define BYTECODE_DECODER(x) (x)
+#endif
+
+
 #if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER
 #define DIRECT_THREADED
@@ -706,5 +843,5 @@
 #ifndef DIRECT_THREADED
 
-#define INIT_DISPATCH for (;;) { i = *pc; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) {
+#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
@@ -716,6 +853,6 @@
 #define INIT_DISPATCH JUMP; return mrb_nil_value();
 #define CASE(op) L_ ## op:
-#define NEXT i=*++pc; CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)]
-#define JUMP i=*pc; CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)]
+#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 END_DISPATCH
@@ -723,17 +860,41 @@
 #endif
 
-#define CALL_MAXARGS 127
-
-void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args);
-
 MRB_API mrb_value
-mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
+{
+  mrb_irep *irep = proc->body.irep;
+  mrb_value result;
+  struct mrb_context *c = mrb->c;
+  int cioff = c->ci - c->cibase;
+  unsigned int nregs = irep->nregs;
+
+  if (!c->stack) {
+    stack_init(mrb);
+  }
+  if (stack_keep > nregs)
+    nregs = stack_keep;
+  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);
+  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;
+  }
+  return result;
+}
+
+MRB_API mrb_value
+mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
 {
   /* 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);
@@ -773,16 +934,13 @@
   if (exc_catched) {
     exc_catched = FALSE;
+    if (mrb->exc && mrb->exc->tt == MRB_TT_BREAK)
+      goto L_BREAK;
     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;
-  regs = mrb->c->stack;
-  regs[0] = self;
-
+
+#define regs (mrb->c->stack)
   INIT_DISPATCH {
     CASE(OP_NOP) {
@@ -793,5 +951,7 @@
     CASE(OP_MOVE) {
       /* A B    R(A) := R(B) */
-      regs[GETARG_A(i)] = regs[GETARG_B(i)];
+      int a = GETARG_A(i);
+      int b = GETARG_B(i);
+      regs[a] = regs[b];
       NEXT;
     }
@@ -799,5 +959,15 @@
     CASE(OP_LOADL) {
       /* A Bx   R(A) := Pool(Bx) */
-      regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+#ifdef MRB_WORD_BOXING
+      mrb_value val = pool[bx];
+      if (mrb_float_p(val)) {
+        val = mrb_float_value(mrb, mrb_float(val));
+      }
+      regs[a] = val;
+#else
+      regs[a] = pool[bx];
+#endif
       NEXT;
     }
@@ -811,5 +981,7 @@
     CASE(OP_LOADSYM) {
       /* A Bx   R(A) := Syms(Bx) */
-      SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]);
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+      SET_SYM_VALUE(regs[a], syms[bx]);
       NEXT;
     }
@@ -817,5 +989,6 @@
     CASE(OP_LOADSELF) {
       /* A      R(A) := self */
-      regs[GETARG_A(i)] = regs[0];
+      int a = GETARG_A(i);
+      regs[a] = regs[0];
       NEXT;
     }
@@ -823,5 +996,6 @@
     CASE(OP_LOADT) {
       /* A      R(A) := true */
-      SET_TRUE_VALUE(regs[GETARG_A(i)]);
+      int a = GETARG_A(i);
+      SET_TRUE_VALUE(regs[a]);
       NEXT;
     }
@@ -829,5 +1003,6 @@
     CASE(OP_LOADF) {
       /* A      R(A) := false */
-      SET_FALSE_VALUE(regs[GETARG_A(i)]);
+      int a = GETARG_A(i);
+      SET_FALSE_VALUE(regs[a]);
       NEXT;
     }
@@ -835,11 +1010,16 @@
     CASE(OP_GETGLOBAL) {
       /* A Bx   R(A) := getglobal(Syms(Bx)) */
-      regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]);
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+      mrb_value val = mrb_gv_get(mrb, syms[bx]);
+      regs[a] = val;
       NEXT;
     }
 
     CASE(OP_SETGLOBAL) {
-      /* setglobal(Syms(Bx), R(A)) */
-      mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
+      /* 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]);
       NEXT;
     }
@@ -847,5 +1027,8 @@
     CASE(OP_GETSPECIAL) {
       /* A Bx   R(A) := Special[Bx] */
-      regs[GETARG_A(i)] = mrb_vm_special_get(mrb, GETARG_Bx(i));
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+      mrb_value val = mrb_vm_special_get(mrb, bx);
+      regs[a] = val;
       NEXT;
     }
@@ -853,5 +1036,7 @@
     CASE(OP_SETSPECIAL) {
       /* A Bx   Special[Bx] := R(A) */
-      mrb_vm_special_set(mrb, GETARG_Bx(i), regs[GETARG_A(i)]);
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+      mrb_vm_special_set(mrb, bx, regs[a]);
       NEXT;
     }
@@ -859,11 +1044,16 @@
     CASE(OP_GETIV) {
       /* A Bx   R(A) := ivget(Bx) */
-      regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]);
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+      mrb_value val = mrb_vm_iv_get(mrb, syms[bx]);
+      regs[a] = val;
       NEXT;
     }
 
     CASE(OP_SETIV) {
-      /* ivset(Syms(Bx),R(A)) */
-      mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
+      /* 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]);
       NEXT;
     }
@@ -871,13 +1061,19 @@
     CASE(OP_GETCV) {
       /* A Bx   R(A) := cvget(Syms(Bx)) */
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+      mrb_value val;
       ERR_PC_SET(mrb, pc);
-      regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]);
+      val = mrb_vm_cv_get(mrb, syms[bx]);
       ERR_PC_CLR(mrb);
+      regs[a] = val;
       NEXT;
     }
 
     CASE(OP_SETCV) {
-      /* cvset(Syms(Bx),R(A)) */
-      mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
+      /* 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]);
       NEXT;
     }
@@ -886,10 +1082,12 @@
       /* A Bx    R(A) := constget(Syms(Bx)) */
       mrb_value val;
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+      mrb_sym sym = syms[bx];
 
       ERR_PC_SET(mrb, pc);
-      val = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
+      val = mrb_vm_const_get(mrb, sym);
       ERR_PC_CLR(mrb);
-      regs = mrb->c->stack;
-      regs[GETARG_A(i)] = val;
+      regs[a] = val;
       NEXT;
     }
@@ -897,5 +1095,7 @@
     CASE(OP_SETCONST) {
       /* A Bx   constset(Syms(Bx),R(A)) */
-      mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
+      int a = GETARG_A(i);
+      int bx = GETARG_Bx(i);
+      mrb_vm_const_set(mrb, syms[bx], regs[a]);
       NEXT;
     }
@@ -905,9 +1105,9 @@
       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[GETARG_Bx(i)]);
+      val = mrb_const_get(mrb, regs[a], syms[bx]);
       ERR_PC_CLR(mrb);
-      regs = mrb->c->stack;
       regs[a] = val;
       NEXT;
@@ -917,6 +1117,6 @@
       /* 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]);
+      int bx = GETARG_Bx(i);
+      mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]);
       NEXT;
     }
@@ -924,8 +1124,9 @@
     CASE(OP_GETUPVAR) {
       /* A B C  R(A) := uvget(B,C) */
-      mrb_value *regs_a = regs + GETARG_A(i);
-      int up = GETARG_C(i);
-
-      struct REnv *e = uvenv(mrb, up);
+      int a = GETARG_A(i);
+      int b = GETARG_B(i);
+      int c = GETARG_C(i);
+      mrb_value *regs_a = regs + a;
+      struct REnv *e = uvenv(mrb, c);
 
       if (!e) {
@@ -933,6 +1134,5 @@
       }
       else {
-        int idx = GETARG_B(i);
-        *regs_a = e->stack[idx];
+        *regs_a = e->stack[b];
       }
       NEXT;
@@ -941,13 +1141,17 @@
     CASE(OP_SETUPVAR) {
       /* A B C  uvset(B,C,R(A)) */
-      int up = GETARG_C(i);
-
-      struct REnv *e = uvenv(mrb, up);
+      int a = GETARG_A(i);
+      int b = GETARG_B(i);
+      int c = GETARG_C(i);
+
+      struct REnv *e = uvenv(mrb, c);
 
       if (e) {
-        mrb_value *regs_a = regs + GETARG_A(i);
-        int idx = GETARG_B(i);
-        e->stack[idx] = *regs_a;
-        mrb_write_barrier(mrb, (struct RBasic*)e);
+        mrb_value *regs_a = regs + a;
+
+        if (b < MRB_ENV_STACK_LEN(e)) {
+          e->stack[b] = *regs_a;
+          mrb_write_barrier(mrb, (struct RBasic*)e);
+        }
       }
       NEXT;
@@ -956,5 +1160,6 @@
     CASE(OP_JMP) {
       /* sBx    pc+=sBx */
-      pc += GETARG_sBx(i);
+      int sbx = GETARG_sBx(i);
+      pc += sbx;
       JUMP;
     }
@@ -962,6 +1167,8 @@
     CASE(OP_JMPIF) {
       /* A sBx  if R(A) pc+=sBx */
-      if (mrb_test(regs[GETARG_A(i)])) {
-        pc += GETARG_sBx(i);
+      int a = GETARG_A(i);
+      int sbx = GETARG_sBx(i);
+      if (mrb_test(regs[a])) {
+        pc += sbx;
         JUMP;
       }
@@ -971,6 +1178,8 @@
     CASE(OP_JMPNOT) {
       /* A sBx  if !R(A) pc+=sBx */
-      if (!mrb_test(regs[GETARG_A(i)])) {
-        pc += GETARG_sBx(i);
+      int a = GETARG_A(i);
+      int sbx = GETARG_sBx(i);
+      if (!mrb_test(regs[a])) {
+        pc += sbx;
         JUMP;
       }
@@ -980,17 +1189,52 @@
     CASE(OP_ONERR) {
       /* sBx    pc+=sBx on exception */
+      int sbx = GETARG_sBx(i);
       if (mrb->c->rsize <= mrb->c->ci->ridx) {
-        if (mrb->c->rsize == 0) mrb->c->rsize = 16;
+        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[mrb->c->ci->ridx++] = pc + GETARG_sBx(i);
+      mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx;
       NEXT;
     }
 
     CASE(OP_RESCUE) {
-      /* A      R(A) := exc; clear(exc) */
-      SET_OBJ_VALUE(regs[GETARG_A(i)], mrb->exc);
-      mrb->exc = 0;
+      /* 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;
+
+        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;
+          }
+        }
+        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;
+      }
       NEXT;
     }
@@ -1008,5 +1252,7 @@
     CASE(OP_RAISE) {
       /* A      raise(R(A)) */
-      mrb->exc = mrb_obj_ptr(regs[GETARG_A(i)]);
+      int a = GETARG_A(i);
+
+      mrb_exc_set(mrb, regs[a]);
       goto L_RAISE;
     }
@@ -1014,14 +1260,16 @@
     CASE(OP_EPUSH) {
       /* Bx     ensure_push(SEQ[Bx]) */
+      int bx = GETARG_Bx(i);
       struct RProc *p;
 
-      p = mrb_closure_new(mrb, irep->reps[GETARG_Bx(i)]);
+      p = mrb_closure_new(mrb, irep->reps[bx]);
       /* push ensure_stack */
-      if (mrb->c->esize <= mrb->c->ci->eidx) {
-        if (mrb->c->esize == 0) mrb->c->esize = 16;
+      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);
       }
-      mrb->c->ensure[mrb->c->ci->eidx++] = p;
+      mrb->c->ensure[mrb->c->eidx++] = p;
+      mrb->c->ensure[mrb->c->eidx] = NULL;
       ARENA_RESTORE(mrb, ai);
       NEXT;
@@ -1032,8 +1280,8 @@
       int a = GETARG_A(i);
       mrb_callinfo *ci = mrb->c->ci;
-      int n, eidx = ci->eidx;
-
-      for (n=0; n<a && (ci == mrb->c->cibase || eidx > ci[-1].eidx); n++) {
-        ecall(mrb, --eidx);
+      int n, epos = ci->epos;
+
+      for (n=0; n<a && mrb->c->eidx > epos; n++) {
+        ecall(mrb, --mrb->c->eidx);
         ARENA_RESTORE(mrb, ai);
       }
@@ -1061,15 +1309,34 @@
       struct RProc *m;
       struct RClass *c;
-      mrb_callinfo *ci;
+      mrb_callinfo *ci = mrb->c->ci;
       mrb_value recv, result;
       mrb_sym mid = syms[GETARG_B(i)];
+      int bidx;
+      mrb_value blk;
 
       recv = regs[a];
+      if (n == CALL_MAXARGS) {
+        bidx = a+2;
+      }
+      else {
+        bidx = a+n+1;
+      }
       if (GET_OPCODE(i) != OP_SENDB) {
-        if (n == CALL_MAXARGS) {
-          SET_NIL_VALUE(regs[a+2]);
-        }
-        else {
-          SET_NIL_VALUE(regs[a+n+1]);
+        if (bidx >= ci->nregs) {
+          stack_extend(mrb, bidx+1);
+          ci->nregs = bidx+1;
+        }
+        SET_NIL_VALUE(regs[bidx]);
+        blk = mrb_nil_value();
+      }
+      else {
+        blk = regs[bidx];
+        if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
+          if (bidx >= ci->nregs) {
+            stack_extend(mrb, bidx+1);
+            ci->nregs = bidx+1;
+          }
+          result = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
+          blk = regs[bidx] = result;
         }
       }
@@ -1090,14 +1357,17 @@
             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;
-        }
+        if (n != CALL_MAXARGS) {
+          if (a+2 >= irep->nregs) {
+            stack_extend(mrb, a+3);
+          }
+          regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+          regs[a+2] = blk;
+          n = CALL_MAXARGS;
+        }
+        mrb_ary_unshift(mrb, regs[a+1], sym);
       }
 
@@ -1125,11 +1395,23 @@
         }
         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 (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) && p->env == ci[-1].env) {
+              p->flags |= MRB_PROC_ORPHAN;
+            }
+          }
+        }
         if (!ci->target_class) { /* return from context modifying method (resume/yield) */
-          if (!MRB_PROC_CFUNC_P(ci[-1].proc)) {
+          if (ci->acc == CI_ACC_RESUMED) {
+            mrb->jmp = prev_jmp;
+            return result;
+          }
+          else {
+            mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc));
             proc = ci[-1].proc;
             irep = proc->body.irep;
@@ -1138,5 +1420,7 @@
           }
         }
-        regs = mrb->c->stack = ci->stackent;
+        mrb->c->stack[0] = result;
+        /* pop stackpos */
+        mrb->c->stack = ci->stackent;
         pc = ci->pc;
         cipop(mrb);
@@ -1152,11 +1436,10 @@
         if (n == CALL_MAXARGS) {
           ci->argc = -1;
-          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
+          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs);
         }
         else {
           ci->argc = n;
-          stack_extend(mrb, irep->nregs,  n+2);
-        }
-        regs = mrb->c->stack;
+          stack_extend(mrb, irep->nregs);
+        }
         pc = irep->iseq;
         JUMP;
@@ -1166,4 +1449,5 @@
     CASE(OP_FSEND) {
       /* A B C  R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */
+      /* not implemented yet */
       NEXT;
     }
@@ -1180,7 +1464,13 @@
       ci->proc = m;
       if (m->env) {
-        if (m->env->mid) {
-          ci->mid = m->env->mid;
-        }
+        mrb_sym mid;
+
+        if (MRB_ENV_STACK_SHARED_P(m->env)) {
+          mid = m->env->cxt.c->cibase[m->env->cioff].mid;
+        }
+        else {
+          mid = m->env->cxt.mid;
+        }
+        if (mid) ci->mid = mid;
         if (!m->env->stack) {
           m->env->stack = mrb->c->stack;
@@ -1195,5 +1485,5 @@
         /* pop stackpos */
         ci = mrb->c->ci;
-        regs = mrb->c->stack = ci->stackent;
+        mrb->c->stack = ci->stackent;
         regs[ci->acc] = recv;
         pc = ci->pc;
@@ -1215,12 +1505,16 @@
         syms = irep->syms;
         ci->nregs = irep->nregs;
+        stack_extend(mrb, 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);
-        }
-        regs = mrb->c->stack;
-        regs[0] = m->env->stack[0];
+          if (irep->nregs > 3) {
+            stack_clear(regs+3, irep->nregs-3);
+          }
+        }
+        else if (ci->argc+2 < irep->nregs) {
+          stack_clear(regs+ci->argc+2, irep->nregs-ci->argc-2);
+        }
+        if (m->env) {
+          regs[0] = m->env->stack[0];
+        }
         pc = irep->iseq;
         JUMP;
@@ -1237,10 +1531,12 @@
       int a = GETARG_A(i);
       int n = GETARG_C(i);
-
-      if (mid == 0) {
+      mrb_value blk;
+      int bidx;
+
+      if (mid == 0 || !ci->target_class) {
         mrb_value exc;
 
         exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
-        mrb->exc = mrb_obj_ptr(exc);
+        mrb_exc_set(mrb, exc);
         goto L_RAISE;
       }
@@ -1249,6 +1545,23 @@
       m = mrb_method_search_vm(mrb, &c, mid);
       if (!m) {
-        mid = mrb_intern_lit(mrb, "method_missing");
-        m = mrb_method_search_vm(mrb, &c, mid);
+        mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+        m = mrb_method_search_vm(mrb, &c, missing);
+        if (!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-1) {
+          regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+          n++;
+        }
         if (n == CALL_MAXARGS) {
           mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
@@ -1258,4 +1571,22 @@
           SET_SYM_VALUE(regs[a+1], ci->mid);
         }
+      }
+
+      if (n == CALL_MAXARGS) {
+        bidx = a+2;
+      }
+      else {
+        bidx = a+n+1;
+      }
+      blk = regs[bidx];
+      if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
+        mrb_value result;
+
+        if (bidx >= ci->nregs) {
+          stack_extend(mrb, bidx+1);
+          ci->nregs = bidx+1;
+        }
+        result = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
+        regs[bidx] = result;
       }
 
@@ -1265,4 +1596,6 @@
       ci->proc = m;
       ci->stackent = mrb->c->stack;
+      ci->target_class = c;
+      ci->pc = pc + 1;
       if (n == CALL_MAXARGS) {
         ci->argc = -1;
@@ -1271,6 +1604,4 @@
         ci->argc = n;
       }
-      ci->target_class = c;
-      ci->pc = pc + 1;
 
       /* prepare stack */
@@ -1279,4 +1610,6 @@
 
       if (MRB_PROC_CFUNC_P(m)) {
+        mrb_value v;
+
         if (n == CALL_MAXARGS) {
           ci->nregs = 3;
@@ -1285,11 +1618,27 @@
           ci->nregs = n + 2;
         }
-        mrb->c->stack[0] = m->body.func(mrb, recv);
+        v = m->body.func(mrb, recv);
         mrb_gc_arena_restore(mrb, ai);
         if (mrb->exc) goto L_RAISE;
+        ci = mrb->c->ci;
+        if (!ci->target_class) { /* return from context modifying method (resume/yield) */
+          if (ci->acc == CI_ACC_RESUMED) {
+            mrb->jmp = prev_jmp;
+            return v;
+          }
+          else {
+            mrb_assert(!MRB_PROC_CFUNC_P(ci[-1].proc));
+            proc = ci[-1].proc;
+            irep = proc->body.irep;
+            pool = irep->pool;
+            syms = irep->syms;
+          }
+        }
+        mrb->c->stack[0] = v;
         /* pop stackpos */
-        regs = mrb->c->stack = mrb->c->ci->stackent;
+        mrb->c->stack = ci->stackent;
+        pc = ci->pc;
         cipop(mrb);
-        NEXT;
+        JUMP;
       }
       else {
@@ -1304,10 +1653,9 @@
         ci->nregs = irep->nregs;
         if (n == CALL_MAXARGS) {
-          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
+          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs);
         }
         else {
-          stack_extend(mrb, irep->nregs, ci->argc+2);
-        }
-        regs = mrb->c->stack;
+          stack_extend(mrb, irep->nregs);
+        }
         pc = irep->iseq;
         JUMP;
@@ -1325,14 +1673,16 @@
       mrb_value *stack;
 
+      if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) {
+        mrb_value exc;
+
+      L_NOSUPER:
+        exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
+        mrb_exc_set(mrb, exc);
+        goto L_RAISE;
+      }
       if (lv == 0) stack = regs + 1;
       else {
         struct REnv *e = uvenv(mrb, lv-1);
-        if (!e) {
-          mrb_value exc;
-
-          exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
-          mrb->exc = mrb_obj_ptr(exc);
-          goto L_RAISE;
-        }
+        if (!e) goto L_NOSUPER;
         stack = e->stack + 1;
       }
@@ -1388,7 +1738,4 @@
       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]);
@@ -1410,5 +1757,4 @@
         argv = mrb_ary_ptr(argv[0])->ptr;
       }
-      mrb->c->ci->argc = len;
       if (argc < len) {
         int mlen = m2;
@@ -1424,6 +1770,12 @@
           value_move(&regs[1], argv, argc-mlen); /* m1 + o */
         }
+        if (argc < m1) {
+          stack_clear(&regs[argc+1], m1-argc);
+        }
         if (mlen) {
           value_move(&regs[len-m2+1], &argv[argc-mlen], mlen);
+        }
+        if (mlen < m2) {
+          stack_clear(&regs[len-m2+mlen+1], m2-mlen);
         }
         if (r) {
@@ -1454,4 +1806,9 @@
         pc += o + 1;
       }
+      mrb->c->ci->argc = len;
+      /* clear local (but non-argument) variables */
+      if (irep->nlocals-len-2 > 0) {
+        stack_clear(&regs[len+2], irep->nlocals-len-2);
+      }
       JUMP;
     }
@@ -1474,32 +1831,51 @@
     CASE(OP_RETURN) {
       /* A B     return R(A) (B=normal,in-block return/break) */
+      mrb_callinfo *ci;
+
+      ci = mrb->c->ci;
+      if (ci->mid) {
+        mrb_value blk;
+
+        if (ci->argc < 0) {
+          blk = regs[2];
+        }
+        else {
+          blk = regs[ci->argc+1];
+        }
+        if (mrb_type(blk) == MRB_TT_PROC) {
+          struct RProc *p = mrb_proc_ptr(blk);
+
+          if (!MRB_PROC_STRICT_P(proc) &&
+              ci > mrb->c->cibase && p->env == ci[-1].env) {
+            p->flags |= MRB_PROC_ORPHAN;
+          }
+        }
+      }
+
       if (mrb->exc) {
-        mrb_callinfo *ci;
-        int eidx;
+        mrb_callinfo *ci0;
+        mrb_value *stk;
 
       L_RAISE:
-        ci = mrb->c->ci;
-        mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern_lit(mrb, "lastpc"), mrb_cptr_value(mrb, pc));
-        mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->c->cibase));
-        eidx = ci->eidx;
+        ci0 = ci = mrb->c->ci;
         if (ci == mrb->c->cibase) {
-          if (ci->ridx == 0) goto L_STOP;
+          if (ci->ridx == 0) goto L_FTOP;
           goto L_RESCUE;
         }
+        stk = mrb->c->stack;
         while (ci[0].ridx == ci[-1].ridx) {
           cipop(mrb);
-          ci = mrb->c->ci;
-          mrb->c->stack = ci[1].stackent;
-          if (ci[1].acc == CI_ACC_SKIP && prev_jmp) {
+          mrb->c->stack = ci->stackent;
+          if (ci->acc == CI_ACC_SKIP && prev_jmp) {
             mrb->jmp = prev_jmp;
             MRB_THROW(prev_jmp);
           }
+          ci = mrb->c->ci;
           if (ci == mrb->c->cibase) {
-            while (eidx > 0) {
-              ecall(mrb, --eidx);
-            }
+            mrb->c->stack = stk;
             if (ci->ridx == 0) {
+            L_FTOP:             /* fiber top */
               if (mrb->c == mrb->root_c) {
-                regs = mrb->c->stack = mrb->c->stbase;
+                mrb->c->stack = mrb->c->stbase;
                 goto L_STOP;
               }
@@ -1507,4 +1883,7 @@
                 struct mrb_context *c = mrb->c;
 
+                if (c->fib) {
+                  mrb_write_barrier(mrb, (struct RBasic*)c->fib);
+                }
                 mrb->c = c->prev;
                 c->prev = NULL;
@@ -1516,6 +1895,7 @@
           /* call ensure only when we skip this callinfo */
           if (ci[0].ridx == ci[-1].ridx) {
-            while (eidx > ci[-1].eidx) {
-              ecall(mrb, --eidx);
+            while (mrb->c->eidx > ci->epos) {
+              ecall(mrb, --mrb->c->eidx);
+              ci = mrb->c->ci;
             }
           }
@@ -1527,32 +1907,49 @@
         pool = irep->pool;
         syms = irep->syms;
-        regs = mrb->c->stack = ci[1].stackent;
+        if (ci != ci0) {
+          mrb->c->stack = ci[1].stackent;
+        }
+        stack_extend(mrb, irep->nregs);
         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)];
-
+        int acc;
+        mrb_value v;
+
+        v = regs[GETARG_A(i)];
+        mrb_gc_protect(mrb, v);
         switch (GETARG_B(i)) {
         case OP_R_RETURN:
           /* Fall through to OP_R_NORMAL otherwise */
-          if (proc->env && !MRB_PROC_STRICT_P(proc)) {
+          if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) {
             struct REnv *e = top_env(mrb, proc);
-
-            if (!MRB_ENV_STACK_SHARED_P(e)) {
+            mrb_callinfo *ce;
+
+            if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt.c != mrb->c) {
               localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
               goto L_RAISE;
             }
-            ci = mrb->c->cibase + e->cioff;
-            if (ci == mrb->c->cibase) {
+            
+            ce = mrb->c->cibase + e->cioff;
+            while (ci >= ce) {
+              if (ci->env) {
+                mrb_env_unshare(mrb, ci->env);
+              }
+              if (ci->acc < 0) {
+                localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
+                goto L_RAISE;
+              }
+              ci--;
+            }
+            if (ce == mrb->c->cibase) {
               localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
               goto L_RAISE;
             }
             mrb->c->stack = mrb->c->ci->stackent;
-            mrb->c->ci = ci;
+            mrb->c->ci = ce;
             break;
           }
         case OP_R_NORMAL:
+        NORMAL_RETURN:
           if (ci == mrb->c->cibase) {
             if (!mrb->c->prev) { /* toplevel return */
@@ -1562,6 +1959,9 @@
             if (mrb->c->prev->ci == mrb->c->prev->cibase) {
               mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
-              mrb->exc = mrb_obj_ptr(exc);
+              mrb_exc_set(mrb, exc);
               goto L_RAISE;
+            }
+            while (mrb->c->eidx > 0) {
+              ecall(mrb, --mrb->c->eidx);
             }
             /* automatic yield at the end */
@@ -1573,7 +1973,16 @@
           break;
         case OP_R_BREAK:
+          if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN;
+          if (MRB_PROC_ORPHAN_P(proc)) { 
+            mrb_value exc;
+
+          L_BREAK_ERROR:
+            exc = mrb_exc_new_str_lit(mrb, E_LOCALJUMP_ERROR,
+                                      "break from proc-closure");
+            mrb_exc_set(mrb, exc);
+            goto L_RAISE;
+          }
           if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
-            localjump_error(mrb, LOCALJUMP_ERROR_BREAK);
-            goto L_RAISE;
+            goto L_BREAK_ERROR;
           }
           /* break from fiber block */
@@ -1581,14 +1990,37 @@
             struct mrb_context *c = mrb->c;
 
+            while (mrb->c->eidx > 0) {
+              ecall(mrb, --mrb->c->eidx);
+            }
             mrb->c = c->prev;
             c->prev = NULL;
-          }
-          ci = mrb->c->ci;
+            ci = mrb->c->ci;
+          }
+          if (ci->acc < 0) {
+            while (mrb->c->eidx > mrb->c->ci->epos) {
+              ecall(mrb, --mrb->c->eidx);
+            }
+            ARENA_RESTORE(mrb, ai);
+            mrb->c->vmexec = FALSE;
+            mrb->exc = (struct RObject*)break_new(mrb, proc, v);
+            mrb->jmp = prev_jmp;
+            MRB_THROW(prev_jmp);
+          }
+          if (FALSE) {
+          L_BREAK:
+            v = ((struct RBreak*)mrb->exc)->val;
+            proc = ((struct RBreak*)mrb->exc)->proc;
+            mrb->exc = NULL;
+            ci = mrb->c->ci;
+          }
           mrb->c->stack = ci->stackent;
           mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
           while (ci > mrb->c->ci) {
+            if (ci->env) {
+              mrb_env_unshare(mrb, ci->env);
+            }
             if (ci[-1].acc == CI_ACC_SKIP) {
               mrb->c->ci = ci;
-              break;
+              goto L_BREAK_ERROR;
             }
             ci--;
@@ -1599,16 +2031,24 @@
           break;
         }
-        while (eidx > mrb->c->ci[-1].eidx) {
-          ecall(mrb, --eidx);
-        }
-        cipop(mrb);
-        acc = ci->acc;
-        pc = ci->pc;
-        regs = mrb->c->stack = ci->stackent;
-        if (acc == CI_ACC_SKIP) {
+        while (mrb->c->eidx > mrb->c->ci->epos) {
+          ecall(mrb, --mrb->c->eidx);
+        }
+        if (mrb->c->vmexec && !mrb->c->ci->target_class) {
+          ARENA_RESTORE(mrb, ai);
+          mrb->c->vmexec = FALSE;
           mrb->jmp = prev_jmp;
           return v;
         }
-        DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid)));
+        ci = mrb->c->ci;
+        acc = ci->acc;
+        mrb->c->stack = ci->stackent;
+        cipop(mrb);
+        if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) {
+          ARENA_RESTORE(mrb, ai);
+          mrb->jmp = prev_jmp;
+          return v;
+        }
+        pc = ci->pc;
+        DEBUG(fprintf(stderr, "from :%s\n", mrb_sym2name(mrb, ci->mid)));
         proc = mrb->c->ci->proc;
         irep = proc->body.irep;
@@ -1617,4 +2057,5 @@
 
         regs[acc] = v;
+        ARENA_RESTORE(mrb, ai);
       }
       JUMP;
@@ -1636,7 +2077,19 @@
       if (!m) {
         mrb_value sym = mrb_symbol_value(mid);
-
-        mid = mrb_intern_lit(mrb, "method_missing");
-        m = mrb_method_search_vm(mrb, &c, mid);
+        mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
+        m = mrb_method_search_vm(mrb, &c, missing);
+        if (!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);
@@ -1663,5 +2116,6 @@
 
       if (MRB_PROC_CFUNC_P(m)) {
-        mrb->c->stack[0] = m->body.func(mrb, recv);
+        mrb_value v = m->body.func(mrb, recv);
+        mrb->c->stack[0] = v;
         mrb_gc_arena_restore(mrb, ai);
         goto L_RETURN;
@@ -1673,10 +2127,9 @@
         syms = irep->syms;
         if (ci->argc < 0) {
-          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
+          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs);
         }
         else {
-          stack_extend(mrb, irep->nregs, ci->argc+2);
-        }
-        regs = mrb->c->stack;
+          stack_extend(mrb, irep->nregs);
+        }
         pc = irep->iseq;
       }
@@ -1697,9 +2150,14 @@
       else {
         struct REnv *e = uvenv(mrb, lv-1);
-        if (!e) {
+        if (!e || e->cioff == 0 ||
+            (!MRB_ENV_STACK_SHARED_P(e) && e->cxt.mid == 0)) {
           localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
           goto L_RAISE;
         }
         stack = e->stack + 1;
+      }
+      if (mrb_nil_p(stack[m1+r+m2])) {
+        localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
+        goto L_RAISE;
       }
       regs[a] = stack[m1+r+m2];
@@ -1833,23 +2291,13 @@
       case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
         {
-          mrb_value z;
-
-          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));
-            }
+          mrb_int x, y, z;
+
+          x = mrb_fixnum(regs[a]);
+          y = mrb_fixnum(regs[a+1]);
+          if (mrb_int_mul_overflow(x, y, &z)) {
+            SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * (mrb_float)y);
             break;
-          case MRB_TT_FLOAT:
-            {
-              SET_FLOAT_VALUE(mrb, regs[a], mrb_float(z));
-            }
-            break;
-          default:
-            /* cannot happen */
-            break;
-          }
+          }
+          SET_INT_VALUE(regs[a], z);
         }
         break;
@@ -1936,5 +2384,6 @@
 #ifdef MRB_NAN_BOXING
       if (isnan(mrb_float(regs[a]))) {
-        regs[a] = mrb_float_value(mrb, mrb_float(regs[a]));
+        mrb_value v = mrb_float_value(mrb, mrb_float(regs[a]));
+        regs[a] = v;
       }
 #endif
@@ -2089,5 +2538,9 @@
     CASE(OP_ARRAY) {
       /* A B C          R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
-      regs[GETARG_A(i)] = mrb_ary_new_from_values(mrb, GETARG_C(i), &regs[GETARG_B(i)]);
+      int a = GETARG_A(i);
+      int b = GETARG_B(i);
+      int c = GETARG_C(i);
+      mrb_value v = mrb_ary_new_from_values(mrb, c, &regs[b]);
+      regs[a] = v;
       ARENA_RESTORE(mrb, ai);
       NEXT;
@@ -2096,6 +2549,8 @@
     CASE(OP_ARYCAT) {
       /* A B            mrb_ary_concat(R(A),R(B)) */
-      mrb_ary_concat(mrb, regs[GETARG_A(i)],
-                     mrb_ary_splat(mrb, regs[GETARG_B(i)]));
+      int a = GETARG_A(i);
+      int b = GETARG_B(i);
+      mrb_value splat = mrb_ary_splat(mrb, regs[b]);
+      mrb_ary_concat(mrb, regs[a], splat);
       ARENA_RESTORE(mrb, ai);
       NEXT;
@@ -2104,5 +2559,7 @@
     CASE(OP_ARYPUSH) {
       /* A B            R(A).push(R(B)) */
-      mrb_ary_push(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
+      int a = GETARG_A(i);
+      int b = GETARG_B(i);
+      mrb_ary_push(mrb, regs[a], regs[b]);
       NEXT;
     }
@@ -2111,10 +2568,11 @@
       /* A B C          R(A) := R(B)[C] */
       int a = GETARG_A(i);
+      int b = GETARG_B(i);
       int c = GETARG_C(i);
-      mrb_value v = regs[GETARG_B(i)];
+      mrb_value v = regs[b];
 
       if (!mrb_array_p(v)) {
         if (c == 0) {
-          regs[GETARG_A(i)] = v;
+          regs[a] = v;
         }
         else {
@@ -2123,5 +2581,6 @@
       }
       else {
-        regs[GETARG_A(i)] = mrb_ary_ref(mrb, v, c);
+        v = mrb_ary_ref(mrb, v, c);
+        regs[a] = v;
       }
       NEXT;
@@ -2130,5 +2589,8 @@
     CASE(OP_ASET) {
       /* A B C          R(B)[C] := R(A) */
-      mrb_ary_set(mrb, regs[GETARG_B(i)], GETARG_C(i), regs[GETARG_A(i)]);
+      int a = GETARG_A(i);
+      int b = GETARG_B(i);
+      int c = GETARG_C(i);
+      mrb_ary_set(mrb, regs[b], c, regs[a]);
       NEXT;
     }
@@ -2140,5 +2602,4 @@
       int pre  = GETARG_B(i);
       int post = GETARG_C(i);
-
       struct RArray *ary;
       int len, idx;
@@ -2150,5 +2611,6 @@
       len = ary->len;
       if (len > pre + post) {
-        regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre);
+        v = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre);
+        regs[a++] = v;
         while (post--) {
           regs[a++] = ary->ptr[len-post-1];
@@ -2156,5 +2618,6 @@
       }
       else {
-        regs[a++] = mrb_ary_new_capa(mrb, 0);
+        v = mrb_ary_new_capa(mrb, 0);
+        regs[a++] = v;
         for (idx=0; idx+pre<len; idx++) {
           regs[a+idx] = ary->ptr[pre+idx];
@@ -2171,5 +2634,6 @@
     CASE(OP_STRING) {
       /* A Bx           R(A) := str_new(Lit(Bx)) */
-      regs[GETARG_A(i)] = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
+      mrb_value str = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
+      regs[GETARG_A(i)] = str;
       ARENA_RESTORE(mrb, ai);
       NEXT;
@@ -2179,5 +2643,4 @@
       /* A B    R(A).concat(R(B)) */
       mrb_str_concat(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
-      regs = mrb->c->stack;
       NEXT;
     }
@@ -2224,5 +2687,5 @@
     CASE(OP_CLASS) {
       /* A B    R(A) := newclass(R(A),Syms(B),R(A+1)) */
-      struct RClass *c = 0;
+      struct RClass *c = 0, *baseclass;
       int a = GETARG_A(i);
       mrb_value base, super;
@@ -2232,5 +2695,8 @@
       super = regs[a+1];
       if (mrb_nil_p(base)) {
-        base = mrb_obj_value(mrb->c->ci->target_class);
+        baseclass = mrb->c->ci->proc->target_class;
+        if (!baseclass) baseclass = mrb->c->ci->target_class;
+
+        base = mrb_obj_value(baseclass);
       }
       c = mrb_vm_define_class(mrb, base, super, id);
@@ -2242,5 +2708,5 @@
     CASE(OP_MODULE) {
       /* A B            R(A) := newmodule(R(A),Syms(B)) */
-      struct RClass *c = 0;
+      struct RClass *c = 0, *baseclass;
       int a = GETARG_A(i);
       mrb_value base;
@@ -2249,5 +2715,8 @@
       base = regs[a];
       if (mrb_nil_p(base)) {
-        base = mrb_obj_value(mrb->c->ci->target_class);
+        baseclass = mrb->c->ci->proc->target_class;
+        if (!baseclass) baseclass = mrb->c->ci->target_class;
+
+        base = mrb_obj_value(baseclass);
       }
       c = mrb_vm_define_module(mrb, base, id);
@@ -2263,4 +2732,8 @@
       mrb_value recv = regs[a];
       struct RProc *p;
+
+      /* prepare closure */
+      p = mrb_closure_new(mrb, irep->reps[GETARG_Bx(i)]);
+      p->c = NULL;
 
       /* prepare stack */
@@ -2276,28 +2749,16 @@
       mrb->c->stack += a;
 
-      p = mrb_proc_new(mrb, irep->reps[GETARG_Bx(i)]);
+      /* setup closure */
       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->ci->stackent;
-        cipop(mrb);
-        NEXT;
-      }
-      else {
-        irep = p->body.irep;
-        pool = irep->pool;
-        syms = irep->syms;
-        stack_extend(mrb, irep->nregs, 1);
-        ci->nregs = irep->nregs;
-        regs = mrb->c->stack;
-        pc = irep->iseq;
-        JUMP;
-      }
+      irep = p->body.irep;
+      pool = irep->pool;
+      syms = irep->syms;
+      stack_extend(mrb, irep->nregs);
+      stack_clear(regs+1, irep->nregs-1);
+      ci->nregs = irep->nregs;
+      pc = irep->iseq;
+      JUMP;
     }
 
@@ -2324,5 +2785,5 @@
       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 = mrb_obj_ptr(exc);
+        mrb_exc_set(mrb, exc);
         goto L_RAISE;
       }
@@ -2334,5 +2795,6 @@
       /* A B C  R(A) := range_new(R(B),R(B+1),C) */
       int b = GETARG_B(i);
-      regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
+      mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
+      regs[GETARG_A(i)] = val;
       ARENA_RESTORE(mrb, ai);
       NEXT;
@@ -2357,8 +2819,8 @@
     L_STOP:
       {
-        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);
+        int epos = mrb->c->ci->epos;
+
+        while (mrb->c->eidx > epos) {
+          ecall(mrb, --mrb->c->eidx);
         }
       }
@@ -2382,9 +2844,10 @@
         exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
       }
-      mrb->exc = mrb_obj_ptr(exc);
+      mrb_exc_set(mrb, exc);
       goto L_RAISE;
     }
   }
   END_DISPATCH;
+#undef regs
 
   }
@@ -2399,21 +2862,31 @@
 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) */
+  if (mrb->c->ci->argc < 0) {
+    return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */
+  }
+  else {
+    return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
+  }
 }
 
 MRB_API mrb_value
-mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep)
+mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
 {
   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);
+  if (!mrb->c->cibase) {
+    return mrb_vm_run(mrb, proc, self, stack_keep);
+  }
+  if (mrb->c->ci == mrb->c->cibase) {
+    mrb->c->ci->env = NULL;
+    return mrb_vm_run(mrb, proc, self, stack_keep);
   }
   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_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
+  v = mrb_vm_run(mrb, proc, self, stack_keep);
   cipop(mrb);
 
@@ -2421,7 +2894,11 @@
 }
 
-MRB_API mrb_value
-mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
-{
-  return mrb_toplevel_run_keep(mrb, proc, 0);
-}
+#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus)
+# if !defined(MRB_ENABLE_CXX_ABI)
+} /* end of extern "C" */
+# endif
+mrb_int mrb_jmpbuf::jmpbuf_id = 0;
+# if !defined(MRB_ENABLE_CXX_ABI)
+extern "C" {
+# endif
+#endif
