NODE_SUPER should preserve stack region for block; ref #2136
[mruby.git] / src / codegen.c
index d89fd57..0cecc8d 100644 (file)
@@ -5,6 +5,7 @@
 */
 
 #include <ctype.h>
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include "mruby.h"
@@ -15,7 +16,8 @@
 #include "mruby/debug.h"
 #include "node.h"
 #include "opcode.h"
-#include "re.h"
+#include "mruby/re.h"
+#include "mrb_throw.h"
 
 typedef mrb_ast_node node;
 typedef struct mrb_parser_state parser_state;
@@ -38,7 +40,7 @@ struct loopinfo {
 typedef struct scope {
   mrb_state *mrb;
   mrb_pool *mpool;
-  jmp_buf jmp;
+  struct mrb_jmpbuf jmp;
 
   struct scope *prev;
 
@@ -101,7 +103,7 @@ codegen_error(codegen_scope *s, const char *message)
     fprintf(stderr, "codegen error: %s\n", message);
   }
 #endif
-  longjmp(s->jmp, 1);
+  MRB_THROW(&s->jmp);
 }
 
 static void*
@@ -138,7 +140,7 @@ new_label(codegen_scope *s)
   return s->pc;
 }
 
-static inline void
+static inline int
 genop(codegen_scope *s, mrb_code i)
 {
   if (s->pc == s->icapa) {
@@ -153,13 +155,13 @@ genop(codegen_scope *s, mrb_code i)
   if (s->lines) {
     s->lines[s->pc] = s->lineno;
   }
-  s->pc++;
+  return s->pc++;
 }
 
 #define NOVAL  0
 #define VAL    1
 
-static void
+static int
 genop_peep(codegen_scope *s, mrb_code i, int val)
 {
   /* peephole optimization */
@@ -172,24 +174,24 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
     case OP_MOVE:
       if (GETARG_A(i) == GETARG_B(i)) {
         /* skip useless OP_MOVE */
-        return;
+        return 0;
       }
       if (val) break;
       switch (c0) {
       case OP_MOVE:
         if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0) && GETARG_A(i) >= s->nlocals) {
           /* skip swapping OP_MOVE */
-          return;
+          return 0;
         }
         if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
           s->iseq[s->pc-1] = MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0));
-          return;
+          return 0;
         }
         break;
       case OP_LOADI:
         if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
           s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0));
-          return;
+          return 0;
         }
         break;
       case OP_ARRAY:
@@ -199,7 +201,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
       case OP_GETUPVAR:
         if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
           s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0));
-          return;
+          return 0;
         }
         break;
       case OP_LOADSYM:
@@ -212,13 +214,13 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
       case OP_STRING:
         if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
           s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0));
-          return;
+          return 0;
         }
         break;
       case OP_SCLASS:
         if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
           s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0));
-          return;
+          return 0;
         }
         break;
       case OP_LOADNIL:
@@ -228,7 +230,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
       case OP_OCLASS:
         if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
           s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i));
-          return;
+          return 0;
         }
         break;
       default:
@@ -244,7 +246,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
       if (c0 == OP_MOVE) {
         if (GETARG_A(i) == GETARG_A(i0)) {
           s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i));
-          return;
+          return 0;
         }
       }
       break;
@@ -253,29 +255,32 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
       if (c0 == OP_MOVE) {
         if (GETARG_A(i) == GETARG_A(i0)) {
           s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i));
-          return;
+          return 0;
         }
       }
       break;
     case OP_EPOP:
       if (c0 == OP_EPOP) {
         s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i));
-        return;
+        return 0;
       }
       break;
     case OP_POPERR:
       if (c0 == OP_POPERR) {
         s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i));
-        return;
+        return 0;
       }
       break;
     case OP_RETURN:
       switch (c0) {
       case OP_RETURN:
-        return;
+        return 0;
       case OP_MOVE:
-        s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
-        return;
+        if (GETARG_A(i0) >= s->nlocals) {
+          s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
+          return 0;
+        }
+        break;
       case OP_SETIV:
       case OP_SETCV:
       case OP_SETCONST:
@@ -285,8 +290,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
         s->pc--;
         genop_peep(s, i0, NOVAL);
         i0 = s->iseq[s->pc-1];
-        genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
-        return;
+        return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
 #if 0
       case OP_SEND:
         if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) {
@@ -310,7 +314,7 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
           s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c);
         else
           s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c);
-        return;
+        return 0;
       }
     case OP_STRCAT:
       if (c0 == OP_STRING) {
@@ -319,15 +323,22 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
         if (mrb_type(s->irep->pool[i]) == MRB_TT_STRING &&
             RSTRING_LEN(s->irep->pool[i]) == 0) {
           s->pc--;
-          return;
+          return 0;
         }
       }
       break;
+    case OP_JMPIF:
+    case OP_JMPNOT:
+      if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) {
+        s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i));
+        return s->pc-1;
+      }
+      break;
     default:
       break;
     }
   }
-  genop(s, i);
+  return genop(s, i);
 }
 
 static void
@@ -535,15 +546,15 @@ for_body(codegen_scope *s, node *tree)
   node *n2;
   mrb_code c;
 
-  // generate receiver
+  /* generate receiver */
   codegen(s, tree->cdr->car, VAL);
-  // generate loop-block
+  /* generate loop-block */
   s = scope_new(s->mrb, s, tree->car);
 
   lp = loop_push(s, LOOP_FOR);
   lp->pc1 = new_label(s);
 
-  // generate loop variable
+  /* generate loop variable */
   n2 = tree->car;
   if (n2->car && !n2->car->cdr && !n2->cdr) {
     genop(s, MKOP_Ax(OP_ENTER, 0x40000));
@@ -699,12 +710,17 @@ static mrb_sym
 attrsym(codegen_scope *s, mrb_sym a)
 {
   const char *name;
-  size_t len;
+  mrb_int len;
   char *name2;
 
   name = mrb_sym2name_len(s->mrb, a, &len);
-  name2 = (char *)codegen_palloc(s, len+1);
-  memcpy(name2, name, len);
+  name2 = (char *)codegen_palloc(s,
+                                 (size_t)len
+                                 + 1 /* '=' */
+                                 + 1 /* '\0' */
+                                 );
+  mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
+  memcpy(name2, name, (size_t)len);
   name2[len] = '=';
   name2[len+1] = '\0';
 
@@ -718,7 +734,7 @@ gen_values(codegen_scope *s, node *t, int val)
   int is_splat;
 
   while (t) {
-    is_splat = (intptr_t)t->car->car == NODE_SPLAT; // splat mode
+    is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
     if (n >= 127 || is_splat) {
       if (val) {
         pop_n(n);
@@ -756,7 +772,7 @@ gen_values(codegen_scope *s, node *t, int val)
       }
       return -1;
     }
-    // normal (no splat) mode
+    /* normal (no splat) mode */
     codegen(s, t->car, val);
     n++;
     t = t->cdr;
@@ -803,9 +819,10 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val)
   else {
     blk = cursp();
   }
+  push();pop();
   pop_n(n+1);
   {
-    size_t len;
+    mrb_int len;
     const char *name = mrb_sym2name_len(s->mrb, sym, &len);
 
     if (!noop && len == 1 && name[0] == '+')  {
@@ -1145,8 +1162,7 @@ codegen(codegen_scope *s, node *tree, int val)
       int onerr, noexc, exend, pos1, pos2, tmp;
       struct loopinfo *lp;
 
-      onerr = new_label(s);
-      genop(s, MKOP_Bx(OP_ONERR, 0));
+      onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
       lp = loop_push(s, LOOP_BEGIN);
       lp->pc1 = onerr;
       if (tree->car) {
@@ -1154,8 +1170,7 @@ codegen(codegen_scope *s, node *tree, int val)
         if (val) pop();
       }
       lp->type = LOOP_RESCUE;
-      noexc = new_label(s);
-      genop(s, MKOP_Bx(OP_JMP, 0));
+      noexc = genop(s, MKOP_Bx(OP_JMP, 0));
       dispatch(s, onerr);
       tree = tree->cdr;
       exend = 0;
@@ -1182,16 +1197,19 @@ codegen(codegen_scope *s, node *tree, int val)
             }
             genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
             pop();
-            genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
-            tmp = new_label(s);
-            genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+            if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
+              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+            }
+            else {
+              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
+            }
+            tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
             pos2 = tmp;
             if (n4) {
               n4 = n4->cdr;
             }
           } while (n4);
-          pos1 = new_label(s);
-          genop(s, MKOP_sBx(OP_JMP, 0));
+          pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
           dispatch_linked(s, pos2);
 
           pop();
@@ -1202,8 +1220,7 @@ codegen(codegen_scope *s, node *tree, int val)
             codegen(s, n3->cdr->cdr->car, val);
             if (val) pop();
           }
-          tmp = new_label(s);
-          genop(s, MKOP_sBx(OP_JMP, exend));
+          tmp = genop(s, MKOP_sBx(OP_JMP, exend));
           exend = tmp;
           n2 = n2->cdr;
           push();
@@ -1268,8 +1285,7 @@ codegen(codegen_scope *s, node *tree, int val)
 
       codegen(s, tree->car, VAL);
       pop();
-      pos1 = new_label(s);
-      genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+      pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL);
 
       codegen(s, tree->cdr->car, val);
       if (val && !(tree->cdr->car)) {
@@ -1278,17 +1294,15 @@ codegen(codegen_scope *s, node *tree, int val)
       }
       if (e) {
         if (val) pop();
-        pos2 = new_label(s);
-        genop(s, MKOP_sBx(OP_JMP, 0));
-       dispatch(s, pos1);
+        pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
+        dispatch(s, pos1);
         codegen(s, e, val);
         dispatch(s, pos2);
       }
       else {
         if (val) {
           pop();
-          pos2 = new_label(s);
-          genop(s, MKOP_sBx(OP_JMP, 0));
+          pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
           dispatch(s, pos1);
           genop(s, MKOP_A(OP_LOADNIL, cursp()));
           dispatch(s, pos2);
@@ -1306,9 +1320,8 @@ codegen(codegen_scope *s, node *tree, int val)
       int pos;
 
       codegen(s, tree->car, VAL);
-      pos = new_label(s);
       pop();
-      genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+      pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
       codegen(s, tree->cdr, val);
       dispatch(s, pos);
     }
@@ -1319,9 +1332,8 @@ codegen(codegen_scope *s, node *tree, int val)
       int pos;
 
       codegen(s, tree->car, VAL);
-      pos = new_label(s);
       pop();
-      genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
+      pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
       codegen(s, tree->cdr, val);
       dispatch(s, pos);
     }
@@ -1331,8 +1343,7 @@ codegen(codegen_scope *s, node *tree, int val)
     {
       struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
 
-      lp->pc1 = new_label(s);
-      genop(s, MKOP_sBx(OP_JMP, 0));
+      lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
       lp->pc2 = new_label(s);
       codegen(s, tree->cdr, NOVAL);
       dispatch(s, lp->pc1);
@@ -1348,8 +1359,7 @@ codegen(codegen_scope *s, node *tree, int val)
     {
       struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
 
-      lp->pc1 = new_label(s);
-      genop(s, MKOP_sBx(OP_JMP, 0));
+      lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
       lp->pc2 = new_label(s);
       codegen(s, tree->cdr, NOVAL);
       dispatch(s, lp->pc1);
@@ -1396,20 +1406,17 @@ codegen(codegen_scope *s, node *tree, int val)
           else {
             pop();
           }
-          tmp = new_label(s);
-          genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+          tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
           pos2 = tmp;
           n = n->cdr;
         }
         if (tree->car->car) {
-          pos1 = new_label(s);
-          genop(s, MKOP_sBx(OP_JMP, 0));
+          pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
           dispatch_linked(s, pos2);
         }
         codegen(s, tree->car->cdr, val);
         if (val) pop();
-        tmp = new_label(s);
-        genop(s, MKOP_sBx(OP_JMP, pos3));
+        tmp = genop(s, MKOP_sBx(OP_JMP, pos3));
         pos3 = tmp;
         if (pos1) dispatch(s, pos1);
         tree = tree->cdr;
@@ -1442,7 +1449,7 @@ codegen(codegen_scope *s, node *tree, int val)
     codegen(s, tree->cdr, val);
     if (val) {
       pop(); pop();
-      genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), 0));
+      genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE));
       push();
     }
     break;
@@ -1452,7 +1459,7 @@ codegen(codegen_scope *s, node *tree, int val)
     codegen(s, tree->cdr, val);
     if (val) {
       pop(); pop();
-      genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), 1));
+      genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE));
       push();
     }
     break;
@@ -1499,30 +1506,39 @@ codegen(codegen_scope *s, node *tree, int val)
   case NODE_HASH:
     {
       int len = 0;
+      mrb_bool update = FALSE;
 
       while (tree) {
         codegen(s, tree->car->car, val);
         codegen(s, tree->car->cdr, val);
         len++;
         tree = tree->cdr;
+        if (val && len == 126) {
+          pop_n(len*2);
+          genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
+          if (update) {
+            pop();
+            genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+          }
+          push();
+          update = TRUE;
+          len = 0;
+        }
       }
       if (val) {
         pop_n(len*2);
         genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
+        if (update) {
+          pop();
+          genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+        }
         push();
       }
     }
     break;
 
   case NODE_SPLAT:
-    {
-      int idx = new_msym(s, mrb_intern_lit(s->mrb, "to_a"));
-
-      codegen(s, tree, VAL);
-      pop();
-      genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 0));
-      push();
-    }
+    codegen(s, tree, VAL);
     break;
 
   case NODE_ASGN:
@@ -1538,7 +1554,7 @@ codegen(codegen_scope *s, node *tree, int val)
       int rhs = cursp();
 
       if ((intptr_t)t->car == NODE_ARRAY && nosplat(t->cdr)) {
-        // fixed rhs
+        /* fixed rhs */
         t = t->cdr;
         while (t) {
           codegen(s, t->car, VAL);
@@ -1587,7 +1603,7 @@ codegen(codegen_scope *s, node *tree, int val)
         }
       }
       else {
-        // variable rhs
+        /* variable rhs */
         codegen(s, t, VAL);
         gen_vmassignment(s, tree->car, rhs, val);
       }
@@ -1597,7 +1613,7 @@ codegen(codegen_scope *s, node *tree, int val)
   case NODE_OP_ASGN:
     {
       mrb_sym sym = sym(tree->cdr->car);
-      size_t len;
+      mrb_int len;
       const char *name = mrb_sym2name_len(s->mrb, sym, &len);
       int idx;
 
@@ -1608,8 +1624,7 @@ codegen(codegen_scope *s, node *tree, int val)
         int pos;
 
         pop();
-        pos = new_label(s);
-        genop(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0));
+        pos = genop_peep(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0), NOVAL);
         codegen(s, tree->cdr->cdr->car, VAL);
         pop();
         gen_assignment(s, tree->car, cursp(), val);
@@ -1617,6 +1632,7 @@ codegen(codegen_scope *s, node *tree, int val)
         break;
       }
       codegen(s, tree->cdr->cdr->car, VAL);
+      push(); pop();
       pop(); pop();
 
       idx = new_msym(s, sym);
@@ -1672,6 +1688,7 @@ codegen(codegen_scope *s, node *tree, int val)
       }
       else {
         genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        push(); pop();
       }
       pop_n(n+1);
       if (sendv) n = CALL_MAXARGS;
@@ -1693,12 +1710,12 @@ codegen(codegen_scope *s, node *tree, int val)
       }
       if (s2) ainfo = s2->ainfo;
       genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)));
+      push(); push(); pop();    /* ARGARY pushes two values */
       if (tree && tree->cdr) {
-        push();
         codegen(s, tree->cdr, VAL);
-        pop_n(2);
+        pop();
       }
-      pop();
+      pop(); pop();
       genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS));
       if (val) push();
     }
@@ -1830,7 +1847,7 @@ codegen(codegen_scope *s, node *tree, int val)
       int idx = lv_idx(s, sym(tree));
 
       if (idx > 0) {
-        genop(s, MKOP_AB(OP_MOVE, cursp(), idx));
+        genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL);
       }
       else {
         int lv = 0;
@@ -1911,7 +1928,7 @@ codegen(codegen_scope *s, node *tree, int val)
       mrb_value fix = mrb_fixnum_value((intptr_t)tree);
       mrb_value str = mrb_str_buf_new(mrb, 4);
 
-      mrb_str_buf_cat(mrb, str, "$", 1);
+      mrb_str_cat_lit(mrb, str, "$");
       mrb_str_buf_append(mrb, str, mrb_fixnum_to_str(mrb, fix, 10));
       sym = new_sym(s, mrb_intern_str(mrb, str));
       genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
@@ -1920,7 +1937,7 @@ codegen(codegen_scope *s, node *tree, int val)
     break;
 
   case NODE_ARG:
-    // should not happen
+    /* should not happen */
     break;
 
   case NODE_BLOCK_ARG:
@@ -2077,14 +2094,48 @@ codegen(codegen_scope *s, node *tree, int val)
     gen_literal_array(s, tree, TRUE, val);
     break;
 
+  case NODE_DXSTR:
+    {
+      node *n;
+      int ai = mrb_gc_arena_save(s->mrb);
+      int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
+
+      if (val == NOVAL) { push(); }
+      genop(s, MKOP_A(OP_OCLASS, cursp()));
+      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      push();
+      codegen(s, tree->car, VAL);
+      n = tree->cdr;
+      while (n) {
+        if ((intptr_t)n->car->car == NODE_XSTR) {
+          n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
+          mrb_assert(!n->cdr); /* must be the end */
+        }
+        codegen(s, n->car, VAL);
+        pop(); pop();
+        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+        push();
+        n = n->cdr;
+      }
+      pop();
+      pop();
+      sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
+      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+      if (val == NOVAL) { pop(); }
+      else { push(); }
+      mrb_gc_arena_restore(s->mrb, ai);
+    }
+    break;
+
   case NODE_XSTR:
-    if (val) {
+    {
       char *p = (char*)tree->car;
       size_t len = (intptr_t)tree->cdr;
       int ai = mrb_gc_arena_save(s->mrb);
       int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
       int off = new_lit(s, mrb_str_new(s->mrb, p, len));
 
+      if (val == NOVAL) { push(); }
       genop(s, MKOP_A(OP_OCLASS, cursp()));
       genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
       push();
@@ -2092,8 +2143,9 @@ codegen(codegen_scope *s, node *tree, int val)
       pop();
       sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
       genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+      if (val == NOVAL) { pop(); }
+      else { push(); }
       mrb_gc_arena_restore(s->mrb, ai);
-      push();
     }
     break;
 
@@ -2103,7 +2155,7 @@ codegen(codegen_scope *s, node *tree, int val)
       char *p2 = (char*)tree->cdr;
       int ai = mrb_gc_arena_save(s->mrb);
       int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
-      int off = new_lit(s, mrb_str_new(s->mrb, p1, strlen(p1)));
+      int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1));
       int argc = 1;
 
       genop(s, MKOP_A(OP_OCLASS, cursp()));
@@ -2112,7 +2164,7 @@ codegen(codegen_scope *s, node *tree, int val)
       genop(s, MKOP_ABx(OP_STRING, cursp(), off));
       if (p2) {
         push();
-        off = new_lit(s, mrb_str_new(s->mrb, p2, strlen(p2)));
+        off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
         genop(s, MKOP_ABx(OP_STRING, cursp(), off));
         argc++;
         pop();
@@ -2149,7 +2201,7 @@ codegen(codegen_scope *s, node *tree, int val)
       n = tree->cdr->cdr;
       if (n->car) {
         p = (char*)n->car;
-        off = new_lit(s, mrb_str_new(s->mrb, p, strlen(p)));
+        off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
         codegen(s, tree->car, VAL);
         genop(s, MKOP_ABx(OP_STRING, cursp(), off));
         pop();
@@ -2160,7 +2212,7 @@ codegen(codegen_scope *s, node *tree, int val)
         int off;
 
         push();
-        off = new_lit(s, mrb_str_new(s->mrb, p2, strlen(p2)));
+        off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
         genop(s, MKOP_ABx(OP_STRING, cursp(), off));
         argc++;
         pop();
@@ -2353,6 +2405,7 @@ codegen(codegen_scope *s, node *tree, int val)
       genop(s, MKOP_A(OP_TCLASS, cursp()));
       push();
       genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
+      push(); pop();
       pop();
       genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
       if (val) {
@@ -2451,9 +2504,9 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
   }
   p->lineno = prev->lineno;
 
-  // debug setting
+  /* debug setting */
   p->debug_start_pos = 0;
-  if(p->filename) {
+  if (p->filename) {
     mrb_debug_info_alloc(mrb, p->irep);
     p->irep->filename = p->filename;
     p->irep->lines = p->lines;
@@ -2494,7 +2547,7 @@ scope_finish(codegen_scope *s)
     mrb_debug_info_append_file(mrb, s->irep, s->debug_start_pos, s->pc);
 
     fname_len = strlen(s->filename);
-    fname = codegen_malloc(s, fname_len + 1);
+    fname = (char*)codegen_malloc(s, fname_len + 1);
     memcpy(fname, s->filename, fname_len);
     fname[fname_len] = '\0';
     irep->filename = fname;
@@ -2554,8 +2607,7 @@ loop_break(codegen_scope *s, node *tree)
       if (tree) {
         genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL);
       }
-      tmp = new_label(s);
-      genop(s, MKOP_sBx(OP_JMP, loop->pc3));
+      tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3));
       loop->pc3 = tmp;
     }
     else {
@@ -2579,14 +2631,15 @@ static void
 codedump(mrb_state *mrb, mrb_irep *irep)
 {
 #ifdef ENABLE_STDIO
-  uint32_t i;
+  int i;
   int ai;
   mrb_code c;
 
   if (!irep) return;
   printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", irep,
          irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
-  for (i=0; i<irep->ilen; i++) {
+
+  for (i = 0; i < (int)irep->ilen; i++) {
     ai = mrb_gc_arena_save(mrb);
     printf("%03d ", i);
     c = irep->iseq[i];
@@ -2741,7 +2794,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
       break;
 
     case OP_LAMBDA:
-      printf("OP_LAMBDA\tR%d\tI(%+d)\t%d\n", GETARG_A(c), GETARG_b(c), GETARG_c(c));
+      printf("OP_LAMBDA\tR%d\tI(%+d)\t%d\n", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c));
       break;
     case OP_RANGE:
       printf("OP_RANGE\tR%d\tR%d\t%d\n", GETARG_A(c), GETARG_B(c), GETARG_C(c));
@@ -2852,7 +2905,7 @@ codedump(mrb_state *mrb, mrb_irep *irep)
              mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
       break;
     case OP_EXEC:
-      printf("OP_EXEC\tR%d\tI(%+d)\n", GETARG_A(c), GETARG_Bx(c));
+      printf("OP_EXEC\tR%d\tI(%+d)\n", GETARG_A(c), GETARG_Bx(c)+1);
       break;
     case OP_SCLASS:
       printf("OP_SCLASS\tR%d\tR%d\n", GETARG_A(c), GETARG_B(c));
@@ -2861,10 +2914,14 @@ codedump(mrb_state *mrb, mrb_irep *irep)
       printf("OP_TCLASS\tR%d\n", GETARG_A(c));
       break;
     case OP_ERR:
-      printf("OP_ERR\tL(%d)\n", GETARG_Bx(c));
+      {
+        mrb_value v = irep->pool[GETARG_Bx(c)];
+        mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
+        printf("OP_ERR\t%s\n", RSTRING_PTR(s));
+      }
       break;
     case OP_EPUSH:
-      printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c));
+      printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1);
       break;
     case OP_ONERR:
       printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c));
@@ -2923,15 +2980,16 @@ mrb_generate_code(mrb_state *mrb, parser_state *p)
   scope->parser = p;
   scope->filename = p->filename;
   scope->filename_index = p->current_filename_index;
-  if (setjmp(scope->jmp) == 0) {
-    // prepare irep
+
+  MRB_TRY(&scope->jmp) {
+    /* prepare irep */
     codegen(scope, p->tree, NOVAL);
     proc = mrb_proc_new(mrb, scope->irep);
     mrb_irep_decref(mrb, scope->irep);
     mrb_pool_close(scope->mpool);
     return proc;
   }
-  else {
+  MRB_CATCH(&scope->jmp) {
     if (scope->filename == scope->irep->filename) {
       scope->irep->filename = NULL;
     }
@@ -2939,4 +2997,5 @@ mrb_generate_code(mrb_state *mrb, parser_state *p)
     mrb_pool_close(scope->mpool);
     return NULL;
   }
+  MRB_END_EXC(&scope->jmp);
 }