Imported Upstream version 1.46.0
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-compiler / core / codegen.c
index 927cc3a..c64ffc4 100644 (file)
@@ -102,12 +102,13 @@ codegen_error(codegen_scope *s, const char *message)
   while (s->prev) {
     codegen_scope *tmp = s->prev;
     mrb_free(s->mrb, s->iseq);
+    mrb_free(s->mrb, s->lines);
     mrb_pool_close(s->mpool);
     s = tmp;
   }
 #ifndef MRB_DISABLE_STDIO
   if (s->filename_sym && s->lineno) {
-    const char *filename = mrb_sym2name_len(s->mrb, s->filename_sym, NULL);
+    const char *filename = mrb_sym_name_len(s->mrb, s->filename_sym, NULL);
     fprintf(stderr, "codegen error:%s:%d: %s\n", filename, s->lineno, message);
   }
   else {
@@ -272,8 +273,7 @@ genop_W(codegen_scope *s, mrb_code i, uint32_t a)
 #define NOVAL  0
 #define VAL    1
 
-//static
-mrb_bool
+static mrb_bool
 no_optimize(codegen_scope *s)
 {
   if (s && s->parser && s->parser->no_optimize)
@@ -281,17 +281,8 @@ no_optimize(codegen_scope *s)
   return FALSE;
 }
 
-static
-mrb_bool
-on_eval(codegen_scope *s)
-{
-  if (s && s->parser && s->parser->on_eval)
-    return TRUE;
-  return FALSE;
-}
-
 struct mrb_insn_data
-mrb_decode_insn(mrb_code *pc)
+mrb_decode_insn(const mrb_code *pc)
 {
   struct mrb_insn_data data = { 0 };
   mrb_code insn = READ_B();
@@ -407,9 +398,6 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
   if (no_peephole(s)) {
   normal:
     genop_2(s, OP_MOVE, dst, src);
-    if (on_eval(s)) {
-      genop_0(s, OP_NOP);
-    }
     return;
   }
   else {
@@ -559,7 +547,7 @@ new_lit(codegen_scope *s, mrb_value val)
       mrb_int len;
       pv = &s->irep->pool[i];
 
-      if (mrb_type(*pv) != MRB_TT_STRING) continue;
+      if (!mrb_string_p(*pv)) continue;
       if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue;
       if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0)
         return i;
@@ -570,7 +558,7 @@ new_lit(codegen_scope *s, mrb_value val)
     for (i=0; i<s->irep->plen; i++) {
       mrb_float f1, f2;
       pv = &s->irep->pool[i];
-      if (mrb_type(*pv) != MRB_TT_FLOAT) continue;
+      if (!mrb_float_p(*pv)) continue;
       f1 = mrb_float(*pv);
       f2 = mrb_float(val);
       if (f1 == f2 && !signbit(f1) == !signbit(f2)) return i;
@@ -599,7 +587,7 @@ new_lit(codegen_scope *s, mrb_value val)
 
   switch (mrb_type(val)) {
   case MRB_TT_STRING:
-    *pv = mrb_str_pool(s->mrb, val);
+    *pv = mrb_str_pool(s->mrb, RSTRING_PTR(val), RSTRING_LEN(val), RSTR_NOFREE_P(RSTRING(val)));
     break;
 
 #ifndef MRB_WITHOUT_FLOAT
@@ -674,6 +662,43 @@ lv_idx(codegen_scope *s, mrb_sym id)
   return 0;
 }
 
+static int
+search_upvar(codegen_scope *s, mrb_sym id, int *idx)
+{
+  struct RProc *u;
+  int lv = 0;
+  codegen_scope *up = s->prev;
+
+  while (up) {
+    *idx = lv_idx(up, id);
+    if (*idx > 0) {
+      return lv;
+    }
+    lv ++;
+    up = up->prev;
+  }
+
+  if (lv < 1) lv = 1;
+  u = s->parser->upper;
+  while (u && !MRB_PROC_CFUNC_P(u)) {
+    struct mrb_irep *ir = u->body.irep;
+    uint_fast16_t n = ir->nlocals;
+    const struct mrb_locals *v = ir->lv;
+    for (; n > 1; n --, v ++) {
+      if (v->name == id) {
+        *idx = v->r;
+        return lv - 1;
+      }
+    }
+    if (MRB_PROC_SCOPE_P(u)) break;
+    u = u->upper;
+    lv ++;
+  }
+
+  codegen_error(s, "Can't found local variables");
+  return -1; /* not reached */
+}
+
 static void
 for_body(codegen_scope *s, node *tree)
 {
@@ -686,9 +711,6 @@ for_body(codegen_scope *s, node *tree)
   codegen(s, tree->cdr->car, VAL);
   /* generate loop-block */
   s = scope_new(s->mrb, s, NULL);
-  if (s == NULL) {
-    raise_error(prev, "unexpected scope");
-  }
 
   push();                       /* push for a block parameter */
 
@@ -724,9 +746,6 @@ lambda_body(codegen_scope *s, node *tree, int blk)
 {
   codegen_scope *parent = s;
   s = scope_new(s->mrb, s, tree->car);
-  if (s == NULL) {
-    raise_error(parent, "unexpected scope");
-  }
 
   s->mscope = !blk;
 
@@ -777,7 +796,7 @@ lambda_body(codegen_scope *s, node *tree, int blk)
     s->ainfo = (((ma+oa) & 0x3f) << 7) /* (12bits = 5:1:5:1) */
       | ((ra & 0x1) << 6)
       | ((pa & 0x1f) << 1)
-      | (kd & 0x1);
+      | ((ka | kd) != 0 ? 0x01 : 0x00);
     genop_W(s, OP_ENTER, a);
     /* generate jump table for optional arguments initializer */
     pos = new_label(s);
@@ -792,12 +811,19 @@ lambda_body(codegen_scope *s, node *tree, int blk)
     i = 0;
     while (opt) {
       int idx;
+      mrb_sym id = nsym(opt->car->car);
 
       dispatch(s, pos+i*3+1);
       codegen(s, opt->car->cdr, VAL);
       pop();
-      idx = lv_idx(s, nsym(opt->car->car));
-      gen_move(s, idx, cursp(), 0);
+      idx = lv_idx(s, id);
+      if (idx > 0) {
+        gen_move(s, idx, cursp(), 0);
+      }
+      else {
+        int lv = search_upvar(s, id, &idx);
+        genop_3(s, OP_GETUPVAR, cursp(), idx, lv);
+      }
       i++;
       opt = opt->cdr;
     }
@@ -824,11 +850,19 @@ lambda_body(codegen_scope *s, node *tree, int blk)
         mrb_assert(nint(kwd->car) == NODE_KW_ARG);
 
         if (def_arg) {
+          int idx;
           genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
           jmpif_key_p = genjmp2(s, OP_JMPIF, lv_idx(s, kwd_sym), 0, 0);
           codegen(s, def_arg, VAL);
           pop();
-          gen_move(s, lv_idx(s, kwd_sym), cursp(), 0);
+          idx = lv_idx(s, kwd_sym);
+          if (idx > 0) {
+            gen_move(s, idx, cursp(), 0);
+          }
+          else {
+            int lv = search_upvar(s, kwd_sym, &idx);
+            genop_3(s, OP_GETUPVAR, cursp(), idx, lv);
+          }
           jmp_def_set = genjmp(s, OP_JMP, 0);
           dispatch(s, jmpif_key_p);
         }
@@ -888,9 +922,6 @@ static int
 scope_body(codegen_scope *s, node *tree, int val)
 {
   codegen_scope *scope = scope_new(s->mrb, s, tree->car);
-  if (scope == NULL) {
-    codegen_error(s, "unexpected scope");
-  }
 
   codegen(scope, tree->cdr, VAL);
   gen_return(scope, OP_RETURN, scope->sp-1);
@@ -922,7 +953,7 @@ attrsym(codegen_scope *s, mrb_sym a)
   mrb_int len;
   char *name2;
 
-  name = mrb_sym2name_len(s->mrb, a, &len);
+  name = mrb_sym_name_len(s->mrb, a, &len);
   name2 = (char *)codegen_palloc(s,
                                  (size_t)len
                                  + 1 /* '=' */
@@ -956,7 +987,12 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
         }
         else {
           pop_n(n);
-          genop_2(s, OP_ARRAY, cursp(), n);
+          if (n == 0 && is_splat) {
+            genop_1(s, OP_LOADNIL, cursp());
+          }
+          else {
+            genop_2(s, OP_ARRAY, cursp(), n);
+          }
           push();
           codegen(s, t->car, VAL);
           pop(); pop();
@@ -1041,7 +1077,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
   pop_n(n+1);
   {
     mrb_int symlen;
-    const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen);
+    const char *symname = mrb_sym_name_len(s->mrb, sym, &symlen);
 
     if (!noop && symlen == 1 && symname[0] == '+' && n == 1)  {
       gen_addsub(s, OP_ADD, cursp());
@@ -1107,25 +1143,18 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
     if (idx > 0) {
       if (idx != sp) {
         gen_move(s, idx, sp, val);
-        if (val && on_eval(s)) genop_0(s, OP_NOP);
       }
       break;
     }
     else {                      /* upvar */
-      int lv = 0;
-      codegen_scope *up = s->prev;
-
-      while (up) {
-        idx = lv_idx(up, nsym(tree));
-        if (idx > 0) {
-          genop_3(s, OP_SETUPVAR, sp, idx, lv);
-          break;
-        }
-        lv++;
-        up = up->prev;
-      }
+      int lv = search_upvar(s, nsym(tree), &idx);
+      genop_3(s, OP_SETUPVAR, sp, idx, lv);
     }
     break;
+  case NODE_NVAR:
+    idx = nint(tree);
+    codegen_error(s, "Can't assign to numbered parameter");
+    break;
   case NODE_IVAR:
     idx = new_sym(s, nsym(tree));
     genop_2(s, OP_SETIV, sp, idx);
@@ -1401,7 +1430,7 @@ codegen(codegen_scope *s, node *tree, int val)
   }
   if (s->irep && s->filename_index != tree->filename_index) {
     mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
-    const char *filename = mrb_sym2name_len(s->mrb, fname, NULL);
+    const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
 
     mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
                                filename, s->lines, s->debug_start_pos, s->pc);
@@ -1553,7 +1582,7 @@ codegen(codegen_scope *s, node *tree, int val)
 
   case NODE_IF:
     {
-      int pos1, pos2;
+      int pos1, pos2, nil_p = FALSE;
       node *elsepart = tree->cdr->cdr->car;
 
       if (!tree->car) {
@@ -1570,32 +1599,59 @@ codegen(codegen_scope *s, node *tree, int val)
       case NODE_NIL:
         codegen(s, elsepart, val);
         goto exit;
+      case NODE_CALL:
+        {
+          node *n = tree->car->cdr;
+          mrb_sym mid = nsym(n->cdr->car);
+          mrb_sym mnil = mrb_intern_lit(s->mrb, "nil?");
+          if (mid == mnil && n->cdr->cdr->car == NULL) {
+            nil_p = TRUE;
+            codegen(s, n->car, VAL);
+          }
+        }
+        break;
+      }
+      if (!nil_p) {
+        codegen(s, tree->car, VAL);
       }
-      codegen(s, tree->car, VAL);
       pop();
-      pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
-
-      codegen(s, tree->cdr->car, val);
-      if (elsepart) {
+      if (val || tree->cdr->car) {
+        if (nil_p) {
+          pos2 = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+          pos1 = genjmp(s, OP_JMP, 0);
+          dispatch(s, pos2);
+        }
+        else {
+          pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
+        }
+        codegen(s, tree->cdr->car, val);
         if (val) pop();
-        pos2 = genjmp(s, OP_JMP, 0);
-        dispatch(s, pos1);
-        codegen(s, elsepart, val);
-        dispatch(s, pos2);
-      }
-      else {
-        if (val) {
-          pop();
+        if (elsepart || val) {
           pos2 = genjmp(s, OP_JMP, 0);
           dispatch(s, pos1);
-          genop_1(s, OP_LOADNIL, cursp());
+          codegen(s, elsepart, val);
           dispatch(s, pos2);
-          push();
         }
         else {
           dispatch(s, pos1);
         }
       }
+      else {                    /* empty then-part */
+        if (elsepart) {
+          if (nil_p) {
+            pos1 = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+          }
+          else {
+            pos1 = genjmp2(s, OP_JMPIF, cursp(), 0, val);
+          }
+          codegen(s, elsepart, val);
+          dispatch(s, pos1);
+        }
+        else if (val && !nil_p) {
+          genop_1(s, OP_LOADNIL, cursp());
+          push();
+        }
+      }
     }
     break;
 
@@ -1833,7 +1889,7 @@ codegen(codegen_scope *s, node *tree, int val)
           len++;
         }
         tree = tree->cdr;
-        if (val && len == 255) {
+        if (val && cursp() > 127) {
           pop_n(len*2);
           if (!update) {
             genop_2(s, OP_HASH, cursp(), len);
@@ -1955,7 +2011,7 @@ codegen(codegen_scope *s, node *tree, int val)
     {
       mrb_sym sym = nsym(tree->cdr->car);
       mrb_int len;
-      const char *name = mrb_sym2name_len(s->mrb, sym, &len);
+      const char *name = mrb_sym_name_len(s->mrb, sym, &len);
       int idx, callargs = -1, vsp = -1;
 
       if ((len == 2 && name[0] == '|' && name[1] == '|') &&
@@ -2297,26 +2353,25 @@ codegen(codegen_scope *s, node *tree, int val)
 
       if (idx > 0) {
         gen_move(s, cursp(), idx, val);
-        if (val && on_eval(s)) genop_0(s, OP_NOP);
       }
       else {
-        int lv = 0;
-        codegen_scope *up = s->prev;
-
-        while (up) {
-          idx = lv_idx(up, nsym(tree));
-          if (idx > 0) {
-            genop_3(s, OP_GETUPVAR, cursp(), idx, lv);
-            break;
-          }
-          lv++;
-          up = up->prev;
-        }
+        int lv = search_upvar(s, nsym(tree), &idx);
+        genop_3(s, OP_GETUPVAR, cursp(), idx, lv);
       }
       push();
     }
     break;
 
+  case NODE_NVAR:
+    if (val) {
+      int idx = nint(tree);
+
+      gen_move(s, cursp(), idx, val);
+
+      push();
+    }
+    break;
+
   case NODE_GVAR:
     {
       int sym = new_sym(s, nsym(tree));
@@ -2353,10 +2408,6 @@ codegen(codegen_scope *s, node *tree, int val)
     }
     break;
 
-  case NODE_DEFINED:
-    codegen(s, tree, val);
-    break;
-
   case NODE_BACK_REF:
     if (val) {
       char buf[] = {'$', nchar(tree)};
@@ -2373,7 +2424,7 @@ codegen(codegen_scope *s, node *tree, int val)
       mrb_value str;
       int sym;
 
-      str = mrb_format(mrb, "$%S", mrb_fixnum_value(nint(tree)));
+      str = mrb_format(mrb, "$%d", nint(tree));
       sym = new_sym(s, mrb_intern_str(mrb, str));
       genop_2(s, OP_GETGV, cursp(), sym);
       push();
@@ -2406,12 +2457,20 @@ codegen(codegen_scope *s, node *tree, int val)
       else
 #endif
       {
-        if (i == -1) genop_1(s, OP_LOADI__1, cursp());
-        else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i);
+        if (i < 0) {
+          if (i == -1) genop_1(s, OP_LOADI__1, cursp());
+          else if (i >= -0xff) genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i); 
+          else if (i >= -0x8000) genop_2S(s, OP_LOADI16, cursp(), (uint16_t)i);
+          else goto lit_int;
+        }
         else if (i < 8) genop_1(s, OP_LOADI_0 + (uint8_t)i, cursp());
-        else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), (uint16_t)i);
+        else if (i <= 0xff) genop_2(s, OP_LOADI, cursp(), (uint16_t)i);
+        else if (i <= 0x7fff) genop_2S(s, OP_LOADI16, cursp(), (uint16_t)i);
         else {
-          int off = new_lit(s, mrb_fixnum_value(i));
+          int off;
+
+        lit_int:
+          off = new_lit(s, mrb_fixnum_value(i));
           genop_2(s, OP_LOADL, cursp(), off);
         }
       }
@@ -2467,9 +2526,12 @@ codegen(codegen_scope *s, node *tree, int val)
           else {
 #endif
             if (i == -1) genop_1(s, OP_LOADI__1, cursp());
-            else if (i >= -0xffff) {
+            else if (i >= -0xff) {
               genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i);
             }
+            else if (i >= -0x8000) {
+              genop_2S(s, OP_LOADI16, cursp(), (uint16_t)i);
+            }
             else {
               int off = new_lit(s, mrb_fixnum_value(i));
               genop_2(s, OP_LOADL, cursp(), off);
@@ -2944,7 +3006,11 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
   mrb_pool *pool = mrb_pool_open(mrb);
   codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope));
 
-  if (!p) return NULL;
+  if (!p) {
+    if (prev)
+      codegen_error(prev, "unexpected scope");
+    return NULL;
+  }
   *p = codegen_scope_zero;
   p->mrb = mrb;
   p->mpool = pool;
@@ -3020,6 +3086,9 @@ scope_finish(codegen_scope *s)
   mrb_state *mrb = s->mrb;
   mrb_irep *irep = s->irep;
 
+  if (s->nlocals >= 0x3ff) {
+    codegen_error(s, "too many local variables");
+  }
   irep->flags = 0;
   if (s->iseq) {
     irep->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc);
@@ -3030,7 +3099,7 @@ scope_finish(codegen_scope *s)
   irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen);
   if (s->filename_sym) {
     mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
-    const char *filename = mrb_sym2name_len(s->mrb, fname, NULL);
+    const char *filename = mrb_sym_name_len(s->mrb, fname, NULL);
 
     mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
                                filename, s->lines, s->debug_start_pos, s->pc);
@@ -3134,9 +3203,6 @@ generate_code(mrb_state *mrb, parser_state *p, int val)
   struct RProc *proc;
   struct mrb_jmpbuf *prev_jmp = mrb->jmp;
 
-  if (!scope) {
-    return NULL;
-  }
   scope->mrb = mrb;
   scope->parser = p;
   scope->filename_sym = p->filename_sym;