summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-compiler/core/codegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-compiler/core/codegen.c')
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c1217
1 files changed, 714 insertions, 503 deletions
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index 8ab1b9bc3..5b779b63d 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -5,15 +5,17 @@
*/
#include <ctype.h>
-#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <math.h>
#include <mruby.h>
#include <mruby/compile.h>
#include <mruby/proc.h>
+#include <mruby/dump.h>
#include <mruby/numeric.h>
#include <mruby/string.h>
#include <mruby/debug.h>
+#include <mruby/presym.h>
#include "node.h"
#include <mruby/opcode.h>
#include <mruby/re.h>
@@ -38,8 +40,8 @@ enum looptype {
struct loopinfo {
enum looptype type;
- int pc0, pc1, pc2, pc3, acc;
- int ensure_level;
+ uint32_t pc0, pc1, pc2, pc3;
+ int acc;
struct loopinfo *prev;
};
@@ -53,15 +55,14 @@ typedef struct scope {
node *lv;
uint16_t sp;
- uint16_t pc;
- uint16_t lastpc;
- uint16_t lastlabel;
+ uint32_t pc;
+ uint32_t lastpc;
+ uint32_t lastlabel;
int ainfo:15;
mrb_bool mscope:1;
struct loopinfo *loop;
- int ensure_level;
- char const *filename;
+ mrb_sym filename_sym;
uint16_t lineno;
mrb_code *iseq;
@@ -69,6 +70,10 @@ typedef struct scope {
uint32_t icapa;
mrb_irep *irep;
+ mrb_pool_value *pool;
+ mrb_sym *syms;
+ mrb_irep **reps;
+ struct mrb_irep_catch_handler *catch_table;
uint32_t pcapa, scapa, rcapa;
uint16_t nlocals;
@@ -88,6 +93,15 @@ static struct loopinfo *loop_push(codegen_scope *s, enum looptype t);
static void loop_break(codegen_scope *s, node *tree);
static void loop_pop(codegen_scope *s, int val);
+/*
+ * The search for catch handlers starts at the end of the table in mrb_vm_run().
+ * Therefore, the next handler to be added must meet one of the following conditions.
+ * - Larger start position
+ * - Same start position but smaller end position
+ */
+static int catch_handler_new(codegen_scope *s);
+static void catch_handler_set(codegen_scope *s, int ent, enum mrb_catch_type type, uint32_t begin, uint32_t end, uint32_t target);
+
static void gen_assignment(codegen_scope *s, node *tree, int sp, int val);
static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val);
@@ -100,16 +114,37 @@ codegen_error(codegen_scope *s, const char *message)
if (!s) return;
while (s->prev) {
codegen_scope *tmp = s->prev;
- mrb_free(s->mrb, s->iseq);
+ if (s->irep) {
+ mrb_free(s->mrb, s->iseq);
+ for (int i=0; i<s->irep->plen; i++) {
+ mrb_pool_value *pv = &s->pool[i];
+ if ((pv->tt & 0x3) == IREP_TT_STR || pv->tt == IREP_TT_BIGINT) {
+ mrb_free(s->mrb, (void*)pv->u.str);
+ }
+ }
+ mrb_free(s->mrb, s->pool);
+ mrb_free(s->mrb, s->syms);
+ mrb_free(s->mrb, s->catch_table);
+ if (s->reps) {
+ /* copied from mrb_irep_free() in state.c */
+ for (int i=0; i<s->irep->rlen; i++) {
+ if (s->reps[i])
+ mrb_irep_decref(s->mrb, (mrb_irep*)s->reps[i]);
+ }
+ mrb_free(s->mrb, s->reps);
+ }
+ mrb_free(s->mrb, s->lines);
+ }
mrb_pool_close(s->mpool);
s = tmp;
}
-#ifndef MRB_DISABLE_STDIO
- if (s->filename && s->lineno) {
- fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message);
+#ifndef MRB_NO_STDIO
+ if (s->filename_sym && s->lineno) {
+ const char *filename = mrb_sym_name_len(s->mrb, s->filename_sym, NULL);
+ fprintf(stderr, "%s:%d: %s\n", filename, s->lineno, message);
}
else {
- fprintf(stderr, "codegen error: %s\n", message);
+ fprintf(stderr, "%s\n", message);
}
#endif
MRB_THROW(&s->jmp);
@@ -125,15 +160,6 @@ codegen_palloc(codegen_scope *s, size_t len)
}
static void*
-codegen_malloc(codegen_scope *s, size_t len)
-{
- void *p = mrb_malloc_simple(s->mrb, len);
-
- if (!p) codegen_error(s, "mrb_malloc");
- return p;
-}
-
-static void*
codegen_realloc(codegen_scope *s, void *p, size_t len)
{
p = mrb_realloc_simple(s->mrb, p, len);
@@ -151,22 +177,26 @@ new_label(codegen_scope *s)
static void
emit_B(codegen_scope *s, uint32_t pc, uint8_t i)
{
- if (pc >= MAXARG_S || s->icapa >= MAXARG_S) {
- codegen_error(s, "too big code block");
- }
if (pc >= s->icapa) {
- s->icapa *= 2;
- if (s->icapa > MAXARG_S) {
- s->icapa = MAXARG_S;
+ if (pc == UINT32_MAX) {
+ codegen_error(s, "too big code block");
+ }
+ if (pc >= UINT32_MAX / 2) {
+ pc = UINT32_MAX;
+ }
+ else {
+ s->icapa *= 2;
}
s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
if (s->lines) {
s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa);
- s->irep->lines = s->lines;
}
}
if (s->lines) {
- s->lines[pc] = s->lineno;
+ if (s->lineno > 0 || pc == 0)
+ s->lines[pc] = s->lineno;
+ else
+ s->lines[pc] = s->lines[pc-1];
}
s->iseq[pc] = i;
}
@@ -261,6 +291,14 @@ genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
}
static void
+genop_2SS(codegen_scope *s, mrb_code i, uint16_t a, uint32_t b)
+{
+ genop_1(s, i, a);
+ gen_S(s, b>>16);
+ gen_S(s, b&0xffff);
+}
+
+static void
genop_W(codegen_scope *s, mrb_code i, uint32_t a)
{
uint8_t a1 = (a>>16) & 0xff;
@@ -277,8 +315,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)
@@ -286,23 +323,14 @@ 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();
uint16_t a = 0;
uint16_t b = 0;
- uint8_t c = 0;
+ uint16_t c = 0;
switch (insn) {
#define FETCH_Z() /* empty */
@@ -363,22 +391,44 @@ no_peephole(codegen_scope *s)
return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc;
}
-static uint16_t
-genjmp(codegen_scope *s, mrb_code i, uint16_t pc)
+#define JMPLINK_START UINT32_MAX
+
+static void
+gen_jmpdst(codegen_scope *s, uint32_t pc)
+{
+
+ if (pc == JMPLINK_START) {
+ gen_S(s, 0);
+ }
+ else {
+ uint32_t pos2 = s->pc+2;
+ int32_t off = pc - pos2;
+
+ if (off > INT16_MAX || INT16_MIN > off) {
+ codegen_error(s, "too big jump offset");
+ }
+ gen_S(s, (uint16_t)off);
+ }
+}
+
+static uint32_t
+genjmp(codegen_scope *s, mrb_code i, uint32_t pc)
{
- uint16_t pos;
+ uint32_t pos;
s->lastpc = s->pc;
gen_B(s, i);
pos = s->pc;
- gen_S(s, pc);
+ gen_jmpdst(s, pc);
return pos;
}
-static uint16_t
-genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val)
+#define genjmp_0(s,i) genjmp(s,i,JMPLINK_START)
+
+static uint32_t
+genjmp2(codegen_scope *s, mrb_code i, uint16_t a, uint32_t pc, int val)
{
- uint16_t pos;
+ uint32_t pos;
if (!no_peephole(s) && !val) {
struct mrb_insn_data data = mrb_last_insn(s);
@@ -394,27 +444,24 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val)
gen_B(s, OP_EXT1);
gen_B(s, i);
gen_S(s, a);
- pos = s->pc;
- gen_S(s, pc);
}
else {
gen_B(s, i);
gen_B(s, (uint8_t)a);
- pos = s->pc;
- gen_S(s, pc);
}
+ pos = s->pc;
+ gen_jmpdst(s, pc);
return pos;
}
+#define genjmp2_0(s,i,a,val) genjmp2(s,i,a,JMPLINK_START,val)
+
static void
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 {
@@ -434,7 +481,8 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
s->pc = s->lastpc;
genop_1(s, data.insn, dst);
break;
- case OP_LOADI: case OP_LOADINEG: case OP_LOADL: case OP_LOADSYM:
+ case OP_LOADI: case OP_LOADINEG:
+ case OP_LOADL: case OP_LOADSYM:
case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV:
case OP_GETCONST: case OP_STRING:
case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH:
@@ -468,11 +516,11 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src)
}
static void
-gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx)
+gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst)
{
if (no_peephole(s)) {
normal:
- genop_2(s, op, dst, idx);
+ genop_1(s, op, dst);
return;
}
else {
@@ -493,10 +541,10 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx)
if (data.b >= 128) goto normal;
s->pc = s->lastpc;
if (op == OP_ADD) {
- genop_3(s, OP_ADDI, dst, idx, (uint8_t)data.b);
+ genop_2(s, OP_ADDI, dst, (uint8_t)data.b);
}
else {
- genop_3(s, OP_SUBI, dst, idx, (uint8_t)data.b);
+ genop_2(s, OP_SUBI, dst, (uint8_t)data.b);
}
break;
default:
@@ -505,21 +553,31 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx)
}
}
-static int
-dispatch(codegen_scope *s, uint16_t pos0)
+static uint32_t
+dispatch(codegen_scope *s, uint32_t pos0)
{
- uint16_t newpos;
+ int32_t pos1;
+ int32_t offset;
+ int16_t newpos;
+
+ if (pos0 == JMPLINK_START) return 0;
+ pos1 = pos0 + 2;
+ offset = s->pc - pos1;
+ if (offset > INT16_MAX) {
+ codegen_error(s, "too big jmp offset");
+ }
s->lastlabel = s->pc;
- newpos = PEEK_S(s->iseq+pos0);
- emit_S(s, pos0, s->pc);
- return newpos;
+ newpos = (int16_t)PEEK_S(s->iseq+pos0);
+ emit_S(s, pos0, (uint16_t)offset);
+ if (newpos == 0) return 0;
+ return pos1+newpos;
}
static void
-dispatch_linked(codegen_scope *s, uint16_t pos)
+dispatch_linked(codegen_scope *s, uint32_t pos)
{
- if (pos==0) return;
+ if (pos==JMPLINK_START) return;
for (;;) {
pos = dispatch(s, pos);
if (pos==0) break;
@@ -552,38 +610,91 @@ pop_n_(codegen_scope *s, int n)
#define pop_n(n) pop_n_(s,n)
#define cursp() (s->sp)
-static inline int
+static int
+new_litbn(codegen_scope *s, const char *p, int base, mrb_bool neg)
+{
+ int i;
+ size_t plen;
+ mrb_pool_value *pv;
+
+ plen = strlen(p);
+ if (plen > 255) {
+ codegen_error(s, "integer too big");
+ }
+ for (i=0; i<s->irep->plen; i++) {
+ size_t len;
+ pv = &s->pool[i];
+ if (pv->tt != IREP_TT_BIGINT) continue;
+ len = pv->u.str[0];
+ if (len == plen && pv->u.str[1] == base && memcmp(pv->u.str+2, p, len) == 0)
+ return i;
+ }
+
+ if (s->irep->plen == s->pcapa) {
+ s->pcapa *= 2;
+ s->pool = (mrb_pool_value*)codegen_realloc(s, s->pool, sizeof(mrb_pool_value)*s->pcapa);
+ }
+
+ pv = &s->pool[s->irep->plen];
+ i = s->irep->plen++;
+ {
+ char *buf;
+ pv->tt = IREP_TT_BIGINT;
+ buf = (char*)codegen_realloc(s, NULL, plen+3);
+ buf[0] = (char)plen;
+ buf[1] = base;
+ if (neg) buf[1] = 0x80;
+ memcpy(buf+2, p, plen);
+ buf[plen+2] = '\0';
+ pv->u.str = buf;
+ }
+ return i;
+}
+
+static int
new_lit(codegen_scope *s, mrb_value val)
{
int i;
- mrb_value *pv;
+ mrb_pool_value *pv;
switch (mrb_type(val)) {
case MRB_TT_STRING:
for (i=0; i<s->irep->plen; i++) {
mrb_int len;
- pv = &s->irep->pool[i];
-
- if (mrb_type(*pv) != MRB_TT_STRING) continue;
- if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue;
- if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0)
+ pv = &s->pool[i];
+ if (pv->tt & IREP_TT_NFLAG) continue;
+ len = pv->tt>>2;
+ if (RSTRING_LEN(val) != len) continue;
+ if (memcmp(pv->u.str, RSTRING_PTR(val), len) == 0)
return i;
}
break;
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
for (i=0; i<s->irep->plen; i++) {
- pv = &s->irep->pool[i];
- if (mrb_type(*pv) != MRB_TT_FLOAT) continue;
- if (mrb_float(*pv) == mrb_float(val)) return i;
+ mrb_float f1, f2;
+ pv = &s->pool[i];
+ if (pv->tt != IREP_TT_FLOAT) continue;
+ pv = &s->pool[i];
+ f1 = pv->u.f;
+ f2 = mrb_float(val);
+ if (f1 == f2 && !signbit(f1) == !signbit(f2)) return i;
}
break;
#endif
- case MRB_TT_FIXNUM:
+ case MRB_TT_INTEGER:
for (i=0; i<s->irep->plen; i++) {
- pv = &s->irep->pool[i];
- if (!mrb_fixnum_p(*pv)) continue;
- if (mrb_fixnum(*pv) == mrb_fixnum(val)) return i;
+ mrb_int v = mrb_integer(val);
+ pv = &s->pool[i];
+ if (pv->tt == IREP_TT_INT32) {
+ if (v == pv->u.i32) return i;
+ }
+#ifdef MRB_64BIT
+ else if (pv->tt == IREP_TT_INT64) {
+ if (v == pv->u.i64) return i;
+ }
+ continue;
+#endif
}
break;
default:
@@ -593,26 +704,43 @@ new_lit(codegen_scope *s, mrb_value val)
if (s->irep->plen == s->pcapa) {
s->pcapa *= 2;
- s->irep->pool = (mrb_value *)codegen_realloc(s, s->irep->pool, sizeof(mrb_value)*s->pcapa);
+ s->pool = (mrb_pool_value*)codegen_realloc(s, s->pool, sizeof(mrb_pool_value)*s->pcapa);
}
- pv = &s->irep->pool[s->irep->plen];
+ pv = &s->pool[s->irep->plen];
i = s->irep->plen++;
switch (mrb_type(val)) {
case MRB_TT_STRING:
- *pv = mrb_str_pool(s->mrb, val);
+ if (RSTR_NOFREE_P(RSTRING(val))) {
+ pv->tt = (uint32_t)(RSTRING_LEN(val)<<2) | IREP_TT_SSTR;
+ pv->u.str = RSTRING_PTR(val);
+ }
+ else {
+ char *p;
+ mrb_int len = RSTRING_LEN(val);
+ pv->tt = (uint32_t)(len<<2) | IREP_TT_STR;
+ p = (char*)codegen_realloc(s, NULL, len+1);
+ memcpy(p, RSTRING_PTR(val), len);
+ p[len] = '\0';
+ pv->u.str = p;
+ }
break;
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
case MRB_TT_FLOAT:
-#ifdef MRB_WORD_BOXING
- *pv = mrb_float_pool(s->mrb, mrb_float(val));
+ pv->tt = IREP_TT_FLOAT;
+ pv->u.f = mrb_float(val);
break;
#endif
+ case MRB_TT_INTEGER:
+#ifdef MRB_INT64
+ pv->tt = IREP_TT_INT64;
+ pv->u.i64 = mrb_integer(val);
+#else
+ pv->tt = IREP_TT_INT32;
+ pv->u.i32 = mrb_integer(val);
#endif
- case MRB_TT_FIXNUM:
- *pv = val;
break;
default:
@@ -622,9 +750,6 @@ new_lit(codegen_scope *s, mrb_value val)
return i;
}
-/* maximum symbol numbers */
-#define MAXSYMLEN 0x10000
-
static int
new_sym(codegen_scope *s, mrb_sym sym)
{
@@ -634,13 +759,16 @@ new_sym(codegen_scope *s, mrb_sym sym)
len = s->irep->slen;
for (i=0; i<len; i++) {
- if (s->irep->syms[i] == sym) return i;
+ if (s->syms[i] == sym) return i;
}
if (s->irep->slen >= s->scapa) {
s->scapa *= 2;
- s->irep->syms = (mrb_sym*)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*s->scapa);
+ if (s->scapa > 0xffff) {
+ codegen_error(s, "too many symbols");
+ }
+ s->syms = (mrb_sym*)codegen_realloc(s, s->syms, sizeof(mrb_sym)*s->scapa);
}
- s->irep->syms[s->irep->slen] = sym;
+ s->syms[s->irep->slen] = sym;
return s->irep->slen++;
}
@@ -676,6 +804,47 @@ lv_idx(codegen_scope *s, mrb_sym id)
return 0;
}
+static int
+search_upvar(codegen_scope *s, mrb_sym id, int *idx)
+{
+ const 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)) {
+ const struct mrb_irep *ir = u->body.irep;
+ uint_fast16_t n = ir->nlocals;
+ int i;
+
+ const mrb_sym *v = ir->lv;
+ if (v) {
+ for (i=1; n > 1; n--, v++, i++) {
+ if (*v == id) {
+ *idx = i;
+ 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)
{
@@ -688,9 +857,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 */
@@ -717,7 +883,7 @@ for_body(codegen_scope *s, node *tree)
genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1);
push();pop(); /* space for a block */
pop();
- idx = new_sym(s, mrb_intern_lit(s->mrb, "each"));
+ idx = new_sym(s, MRB_SYM_2(s->mrb, each));
genop_3(s, OP_SENDB, cursp(), idx, 0);
}
@@ -726,9 +892,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;
@@ -737,27 +900,30 @@ lambda_body(codegen_scope *s, node *tree, int blk)
lp->pc0 = new_label(s);
}
tree = tree->cdr;
- if (tree->car) {
+ if (tree->car == NULL) {
+ genop_W(s, OP_ENTER, 0);
+ s->ainfo = 0;
+ }
+ else {
mrb_aspec a;
int ma, oa, ra, pa, ka, kd, ba;
int pos, i;
- node *n, *opt;
+ node *opt;
+ node *margs, *pargs;
node *tail;
/* mandatory arguments */
ma = node_len(tree->car->car);
- n = tree->car->car;
- while (n) {
- n = n->cdr;
- }
+ margs = tree->car->car;
tail = tree->car->cdr->cdr->cdr->cdr;
/* optional arguments */
oa = node_len(tree->car->cdr->car);
/* rest argument? */
ra = tree->car->cdr->cdr->car ? 1 : 0;
- /* mandatory arugments after rest argument */
+ /* mandatory arguments after rest argument */
pa = node_len(tree->car->cdr->cdr->cdr->car);
+ pargs = tree->car->cdr->cdr->cdr->car;
/* keyword arguments */
ka = tail? node_len(tail->cdr->car) : 0;
/* keyword dictionary? */
@@ -777,27 +943,34 @@ 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);
for (i=0; i<oa; i++) {
new_label(s);
- genjmp(s, OP_JMP, 0);
+ genjmp_0(s, OP_JMP);
}
if (oa > 0) {
- genjmp(s, OP_JMP, 0);
+ genjmp_0(s, OP_JMP);
}
opt = tree->car->cdr->car;
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;
}
@@ -805,6 +978,7 @@ lambda_body(codegen_scope *s, node *tree, int blk)
dispatch(s, pos+i*3+1);
}
+ /* keyword arguments */
if (tail) {
node *kwds = tail->cdr->car;
int kwrest = 0;
@@ -823,12 +997,20 @@ lambda_body(codegen_scope *s, node *tree, int blk)
mrb_assert(nint(kwd->car) == NODE_KW_ARG);
if (def_arg) {
- genop_2(s, OP_KEY_P, cursp(), new_sym(s, kwd_sym));
- jmpif_key_p = genjmp2(s, OP_JMPIF, cursp(), 0, 0);
+ int idx;
+ genop_2(s, OP_KEY_P, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+ jmpif_key_p = genjmp2_0(s, OP_JMPIF, lv_idx(s, kwd_sym), NOVAL);
codegen(s, def_arg, VAL);
pop();
- gen_move(s, lv_idx(s, kwd_sym), cursp(), 0);
- jmp_def_set = genjmp(s, OP_JMP, 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_0(s, OP_JMP);
dispatch(s, jmpif_key_p);
}
genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
@@ -843,7 +1025,34 @@ lambda_body(codegen_scope *s, node *tree, int blk)
genop_0(s, OP_KEYEND);
}
}
+
+ /* argument destructuring */
+ if (margs) {
+ node *n = margs;
+
+ pos = 1;
+ while (n) {
+ if (nint(n->car->car) == NODE_MASGN) {
+ gen_vmassignment(s, n->car->cdr->car, pos, NOVAL);
+ }
+ pos++;
+ n = n->cdr;
+ }
+ }
+ if (pargs) {
+ node *n = margs;
+
+ pos = ma+oa+ra+1;
+ while (n) {
+ if (nint(n->car->car) == NODE_MASGN) {
+ gen_vmassignment(s, n->car->cdr->car, pos, NOVAL);
+ }
+ pos++;
+ n = n->cdr;
+ }
+ }
}
+
codegen(s, tree->cdr->car, VAL);
pop();
if (s->pc > 0) {
@@ -860,9 +1069,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);
@@ -894,7 +1100,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 /* '=' */
@@ -928,7 +1134,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();
@@ -973,16 +1184,15 @@ static void
gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
{
mrb_sym sym = name ? name : nsym(tree->cdr->car);
- int idx, skip = 0;
+ int skip = 0;
int n = 0, noop = 0, sendv = 0, blk = 0;
codegen(s, tree->car, VAL); /* receiver */
if (safe) {
int recv = cursp()-1;
gen_move(s, cursp(), recv, 1);
- skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
+ skip = genjmp2_0(s, OP_JMPNIL, cursp(), val);
}
- idx = new_sym(s, sym);
tree = tree->cdr->cdr->car;
if (tree) {
n = gen_values(s, tree->car, VAL, sp?1:0);
@@ -1014,36 +1224,38 @@ 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(), idx);
+ gen_addsub(s, OP_ADD, cursp());
}
else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) {
- gen_addsub(s, OP_SUB, cursp(), idx);
+ gen_addsub(s, OP_SUB, cursp());
}
else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) {
- genop_2(s, OP_MUL, cursp(), idx);
+ genop_1(s, OP_MUL, cursp());
}
else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) {
- genop_2(s, OP_DIV, cursp(), idx);
+ genop_1(s, OP_DIV, cursp());
}
else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) {
- genop_2(s, OP_LT, cursp(), idx);
+ genop_1(s, OP_LT, cursp());
}
else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) {
- genop_2(s, OP_LE, cursp(), idx);
+ genop_1(s, OP_LE, cursp());
}
else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) {
- genop_2(s, OP_GT, cursp(), idx);
+ genop_1(s, OP_GT, cursp());
}
else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) {
- genop_2(s, OP_GE, cursp(), idx);
+ genop_1(s, OP_GE, cursp());
}
else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) {
- genop_2(s, OP_EQ, cursp(), idx);
+ genop_1(s, OP_EQ, cursp());
}
else {
+ int idx = new_sym(s, sym);
+
if (sendv) {
genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx);
}
@@ -1072,30 +1284,24 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
idx = new_sym(s, nsym(tree));
genop_2(s, OP_SETGV, sp, idx);
break;
+ case NODE_ARG:
case NODE_LVAR:
idx = lv_idx(s, nsym(tree));
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);
@@ -1137,9 +1343,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
break;
default:
-#ifndef MRB_DISABLE_STDIO
- fprintf(stderr, "unknown lhs %d\n", type);
-#endif
+ codegen_error(s, "unknown lhs");
break;
}
if (val) push();
@@ -1179,7 +1383,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
pop_n(post+1);
genop_3(s, OP_APOST, cursp(), n, post);
n = 1;
- if (t->car) { /* rest */
+ if (t->car && t->car != (node*)-1) { /* rest */
gen_assignment(s, t->car, cursp(), NOVAL);
}
if (t->cdr && t->cdr->car) {
@@ -1266,70 +1470,37 @@ raise_error(codegen_scope *s, const char *msg)
genop_1(s, OP_ERR, idx);
}
-#ifndef MRB_WITHOUT_FLOAT
-static double
-readint_float(codegen_scope *s, const char *p, int base)
-{
- const char *e = p + strlen(p);
- double f = 0;
- int n;
-
- if (*p == '+') p++;
- while (p < e) {
- char c = *p;
- c = tolower((unsigned char)c);
- for (n=0; n<base; n++) {
- if (mrb_digitmap[n] == c) {
- f *= base;
- f += n;
- break;
- }
- }
- if (n == base) {
- codegen_error(s, "malformed readint input");
- }
- p++;
- }
- return f;
-}
-#endif
-
static mrb_int
-readint_mrb_int(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_bool *overflow)
+readint(codegen_scope *s, const char *p, int base, mrb_bool *overflow)
{
const char *e = p + strlen(p);
mrb_int result = 0;
- int n;
mrb_assert(base >= 2 && base <= 36);
if (*p == '+') p++;
while (p < e) {
+ int n;
char c = *p;
- c = tolower((unsigned char)c);
- for (n=0; n<base; n++) {
- if (mrb_digitmap[n] == c) {
- break;
- }
- }
- if (n == base) {
+ switch (c) {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ n = c - '0'; break;
+ case '8': case '9':
+ n = c - '0'; break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ n = c - 'a' + 10; break;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ n = c - 'A' + 10; break;
+ default:
codegen_error(s, "malformed readint input");
+ *overflow = TRUE;
+ /* not reached */
+ return result;
}
-
- if (neg) {
- if ((MRB_INT_MIN + n)/base > result) {
- *overflow = TRUE;
- return 0;
- }
- result *= base;
- result -= n;
- }
- else {
- if ((MRB_INT_MAX - n)/base < result) {
- *overflow = TRUE;
- return 0;
- }
- result *= base;
- result += n;
+ if (mrb_int_mul_overflow(result, base, &result) ||
+ mrb_int_add_overflow(result, n, &result)) {
+ *overflow = TRUE;
+ return 0;
}
p++;
}
@@ -1370,11 +1541,14 @@ codegen(codegen_scope *s, node *tree, int val)
codegen_error(s, "too complex expression");
}
if (s->irep && s->filename_index != tree->filename_index) {
- s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
- mrb_debug_info_append_file(s->mrb, s->irep, s->debug_start_pos, s->pc);
+ mrb_sym fname = mrb_parser_get_filename(s->parser, s->filename_index);
+ 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);
s->debug_start_pos = s->pc;
s->filename_index = tree->filename_index;
- s->filename = mrb_parser_get_filename(s->parser, tree->filename_index);
+ s->filename_sym = mrb_parser_get_filename(s->parser, tree->filename_index);
}
nt = nint(tree->car);
@@ -1394,21 +1568,25 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_RESCUE:
{
- int noexc, exend, pos1, pos2, tmp;
+ int noexc;
+ uint32_t exend, pos1, pos2, tmp;
struct loopinfo *lp;
+ int catch_entry, begin, end;
if (tree->car == NULL) goto exit;
lp = loop_push(s, LOOP_BEGIN);
lp->pc0 = new_label(s);
- lp->pc1 = genjmp(s, OP_ONERR, 0);
+ catch_entry = catch_handler_new(s);
+ begin = s->pc;
codegen(s, tree->car, VAL);
pop();
lp->type = LOOP_RESCUE;
- noexc = genjmp(s, OP_JMP, 0);
- dispatch(s, lp->pc1);
+ end = s->pc;
+ noexc = genjmp_0(s, OP_JMP);
+ catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc);
tree = tree->cdr;
- exend = 0;
- pos1 = 0;
+ exend = JMPLINK_START;
+ pos1 = JMPLINK_START;
if (tree->car) {
node *n2 = tree->car;
int exc = cursp();
@@ -1419,22 +1597,22 @@ codegen(codegen_scope *s, node *tree, int val)
node *n3 = n2->car;
node *n4 = n3->car;
- if (pos1) dispatch(s, pos1);
- pos2 = 0;
+ dispatch(s, pos1);
+ pos2 = JMPLINK_START;
do {
if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) {
codegen(s, n4->car, VAL);
gen_move(s, cursp(), exc, 0);
push_n(2); pop_n(2); /* space for one arg and a block */
pop();
- genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1);
+ genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1);
}
else {
if (n4) {
codegen(s, n4->car, VAL);
}
else {
- genop_2(s, OP_GETCONST, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "StandardError")));
+ genop_2(s, OP_GETCONST, cursp(), new_sym(s, MRB_SYM_2(s->mrb, StandardError)));
push();
}
pop();
@@ -1446,7 +1624,7 @@ codegen(codegen_scope *s, node *tree, int val)
n4 = n4->cdr;
}
} while (n4);
- pos1 = genjmp(s, OP_JMP, 0);
+ pos1 = genjmp_0(s, OP_JMP);
dispatch_linked(s, pos2);
pop();
@@ -1462,15 +1640,14 @@ codegen(codegen_scope *s, node *tree, int val)
n2 = n2->cdr;
push();
}
- if (pos1) {
+ if (pos1 != JMPLINK_START) {
dispatch(s, pos1);
- genop_1(s, OP_RAISE, exc);
+ genop_1(s, OP_RAISEIF, exc);
}
}
pop();
tree = tree->cdr;
dispatch(s, noexc);
- genop_1(s, OP_POPERR, 1);
if (tree->car) {
codegen(s, tree->car, val);
}
@@ -1486,14 +1663,22 @@ codegen(codegen_scope *s, node *tree, int val)
if (!tree->cdr || !tree->cdr->cdr ||
(nint(tree->cdr->cdr->car) == NODE_BEGIN &&
tree->cdr->cdr->cdr)) {
+ int catch_entry, begin, end, target;
int idx;
- s->ensure_level++;
- idx = scope_body(s, tree->cdr, NOVAL);
- genop_1(s, OP_EPUSH, idx);
+ catch_entry = catch_handler_new(s);
+ begin = s->pc;
codegen(s, tree->car, val);
- s->ensure_level--;
- genop_1(s, OP_EPOP, 1);
+ end = target = s->pc;
+ push();
+ idx = cursp();
+ genop_1(s, OP_EXCEPT, idx);
+ push();
+ codegen(s, tree->cdr->cdr, NOVAL);
+ pop();
+ genop_1(s, OP_RAISEIF, idx);
+ pop();
+ catch_handler_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target);
}
else { /* empty ensure ignored */
codegen(s, tree->car, val);
@@ -1520,7 +1705,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) {
@@ -1537,32 +1722,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_SYM_Q_2(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_0(s, OP_JMPNIL, cursp(), val);
+ pos1 = genjmp_0(s, OP_JMP);
+ dispatch(s, pos2);
+ }
+ else {
+ pos1 = genjmp2_0(s, OP_JMPNOT, cursp(), 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();
- pos2 = genjmp(s, OP_JMP, 0);
+ if (elsepart || val) {
+ pos2 = genjmp_0(s, OP_JMP);
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_0(s, OP_JMPNIL, cursp(), val);
+ }
+ else {
+ pos1 = genjmp2_0(s, OP_JMPIF, cursp(), val);
+ }
+ codegen(s, elsepart, val);
+ dispatch(s, pos1);
+ }
+ else if (val && !nil_p) {
+ genop_1(s, OP_LOADNIL, cursp());
+ push();
+ }
+ }
}
break;
@@ -1572,7 +1784,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
- pos = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
+ pos = genjmp2_0(s, OP_JMPNOT, cursp(), val);
codegen(s, tree->cdr, val);
dispatch(s, pos);
}
@@ -1584,7 +1796,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
- pos = genjmp2(s, OP_JMPIF, cursp(), 0, val);
+ pos = genjmp2_0(s, OP_JMPIF, cursp(), val);
codegen(s, tree->cdr, val);
dispatch(s, pos);
}
@@ -1595,7 +1807,7 @@ codegen(codegen_scope *s, node *tree, int val)
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
lp->pc0 = new_label(s);
- lp->pc1 = genjmp(s, OP_JMP, 0);
+ lp->pc1 = genjmp_0(s, OP_JMP);
lp->pc2 = new_label(s);
codegen(s, tree->cdr, NOVAL);
dispatch(s, lp->pc1);
@@ -1612,7 +1824,7 @@ codegen(codegen_scope *s, node *tree, int val)
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
lp->pc0 = new_label(s);
- lp->pc1 = genjmp(s, OP_JMP, 0);
+ lp->pc1 = genjmp_0(s, OP_JMP);
lp->pc2 = new_label(s);
codegen(s, tree->cdr, NOVAL);
dispatch(s, lp->pc1);
@@ -1632,10 +1844,10 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_CASE:
{
int head = 0;
- int pos1, pos2, pos3, tmp;
+ uint32_t pos1, pos2, pos3, tmp;
node *n;
- pos3 = 0;
+ pos3 = JMPLINK_START;
if (tree->car) {
head = cursp();
codegen(s, tree->car, VAL);
@@ -1643,17 +1855,17 @@ codegen(codegen_scope *s, node *tree, int val)
tree = tree->cdr;
while (tree) {
n = tree->car->car;
- pos1 = pos2 = 0;
+ pos1 = pos2 = JMPLINK_START;
while (n) {
codegen(s, n->car, VAL);
if (head) {
gen_move(s, cursp(), head, 0);
push(); push(); pop(); pop(); pop();
if (nint(n->car->car) == NODE_SPLAT) {
- genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1);
+ genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, __case_eqq)), 1);
}
else {
- genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "===")), 1);
+ genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_OPSYM_2(s->mrb, eqq)), 1);
}
}
else {
@@ -1664,20 +1876,20 @@ codegen(codegen_scope *s, node *tree, int val)
n = n->cdr;
}
if (tree->car->car) {
- pos1 = genjmp(s, OP_JMP, 0);
+ pos1 = genjmp_0(s, OP_JMP);
dispatch_linked(s, pos2);
}
codegen(s, tree->car->cdr, val);
if (val) pop();
tmp = genjmp(s, OP_JMP, pos3);
pos3 = tmp;
- if (pos1) dispatch(s, pos1);
+ dispatch(s, pos1);
tree = tree->cdr;
}
if (val) {
- int pos = cursp();
+ uint32_t pos = cursp();
genop_1(s, OP_LOADNIL, cursp());
- if (pos3) dispatch_linked(s, pos3);
+ if (pos3 != JMPLINK_START) dispatch_linked(s, pos3);
if (head) pop();
if (cursp() != pos) {
gen_move(s, cursp(), pos, 0);
@@ -1685,7 +1897,7 @@ codegen(codegen_scope *s, node *tree, int val)
push();
}
else {
- if (pos3) {
+ if (pos3 != JMPLINK_START) {
dispatch_linked(s, pos3);
}
if (head) {
@@ -1800,7 +2012,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);
@@ -1922,24 +2134,26 @@ 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] == '|') &&
(nint(tree->car->car) == NODE_CONST ||
nint(tree->car->car) == NODE_CVAR)) {
- int onerr, noexc, exc;
+ int catch_entry, begin, end;
+ int noexc, exc;
struct loopinfo *lp;
- onerr = genjmp(s, OP_ONERR, 0);
lp = loop_push(s, LOOP_BEGIN);
- lp->pc1 = onerr;
+ lp->pc0 = new_label(s);
+ catch_entry = catch_handler_new(s);
+ begin = s->pc;
exc = cursp();
codegen(s, tree->car, VAL);
+ end = s->pc;
+ noexc = genjmp_0(s, OP_JMP);
lp->type = LOOP_RESCUE;
- genop_1(s, OP_POPERR, 1);
- noexc = genjmp(s, OP_JMP, 0);
- dispatch(s, onerr);
+ catch_handler_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc);
genop_1(s, OP_EXCEPT, exc);
genop_1(s, OP_LOADF, exc);
dispatch(s, noexc);
@@ -1990,10 +2204,10 @@ codegen(codegen_scope *s, node *tree, int val)
if (vsp >= 0) {
gen_move(s, vsp, cursp(), 1);
}
- pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val);
+ pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val);
}
else {
- pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val);
+ pos = genjmp2_0(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), val);
}
codegen(s, tree->cdr->cdr->car, VAL);
pop();
@@ -2023,32 +2237,32 @@ codegen(codegen_scope *s, node *tree, int val)
push(); pop();
pop(); pop();
- idx = new_sym(s, sym);
if (len == 1 && name[0] == '+') {
- gen_addsub(s, OP_ADD, cursp(), idx);
+ gen_addsub(s, OP_ADD, cursp());
}
else if (len == 1 && name[0] == '-') {
- gen_addsub(s, OP_SUB, cursp(), idx);
+ gen_addsub(s, OP_SUB, cursp());
}
else if (len == 1 && name[0] == '*') {
- genop_2(s, OP_MUL, cursp(), idx);
+ genop_1(s, OP_MUL, cursp());
}
else if (len == 1 && name[0] == '/') {
- genop_2(s, OP_DIV, cursp(), idx);
+ genop_1(s, OP_DIV, cursp());
}
else if (len == 1 && name[0] == '<') {
- genop_2(s, OP_LT, cursp(), idx);
+ genop_1(s, OP_LT, cursp());
}
else if (len == 2 && name[0] == '<' && name[1] == '=') {
- genop_2(s, OP_LE, cursp(), idx);
+ genop_1(s, OP_LE, cursp());
}
else if (len == 1 && name[0] == '>') {
- genop_2(s, OP_GT, cursp(), idx);
+ genop_1(s, OP_GT, cursp());
}
else if (len == 2 && name[0] == '>' && name[1] == '=') {
- genop_2(s, OP_GE, cursp(), idx);
+ genop_1(s, OP_GE, cursp());
}
else {
+ idx = new_sym(s, sym);
genop_3(s, OP_SEND, cursp(), idx, 1);
}
if (callargs < 0) {
@@ -2124,7 +2338,9 @@ codegen(codegen_scope *s, node *tree, int val)
s2 = s2->prev;
if (!s2) break;
}
- if (s2) ainfo = s2->ainfo;
+ if (s2 && s2->ainfo > 0) {
+ ainfo = s2->ainfo;
+ }
genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf));
push(); push(); pop(); /* ARGARY pushes two values */
if (tree && tree->cdr) {
@@ -2156,7 +2372,7 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_YIELD:
{
codegen_scope *s2 = s;
- int lv = 0, ainfo = 0;
+ int lv = 0, ainfo = -1;
int n = 0, sendv = 0;
while (!s2->mscope) {
@@ -2164,7 +2380,10 @@ codegen(codegen_scope *s, node *tree, int val)
s2 = s2->prev;
if (!s2) break;
}
- if (s2) ainfo = s2->ainfo;
+ if (s2) {
+ ainfo = s2->ainfo;
+ }
+ if (ainfo < 0) codegen_error(s, "invalid yield (SyntaxError)");
push();
if (tree) {
n = gen_values(s, tree, VAL, 0);
@@ -2177,7 +2396,7 @@ codegen(codegen_scope *s, node *tree, int val)
pop_n(n+1);
genop_2S(s, OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf));
if (sendv) n = CALL_MAXARGS;
- genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "call")), n);
+ genop_3(s, OP_SEND, cursp(), new_sym(s, MRB_SYM_2(s->mrb, call)), n);
if (val) push();
}
break;
@@ -2192,11 +2411,8 @@ codegen(codegen_scope *s, node *tree, int val)
raise_error(s, "unexpected next");
}
else if (s->loop->type == LOOP_NORMAL) {
- if (s->ensure_level > s->loop->ensure_level) {
- genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
- }
codegen(s, tree, NOVAL);
- genjmp(s, OP_JMP, s->loop->pc0);
+ genjmp(s, OP_JMPUW, s->loop->pc0);
}
else {
if (tree) {
@@ -2216,10 +2432,7 @@ codegen(codegen_scope *s, node *tree, int val)
raise_error(s, "unexpected redo");
}
else {
- if (s->ensure_level > s->loop->ensure_level) {
- genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
- }
- genjmp(s, OP_JMP, s->loop->pc2);
+ genjmp(s, OP_JMPUW, s->loop->pc2);
}
if (val) push();
break;
@@ -2227,32 +2440,16 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_RETRY:
{
const char *msg = "unexpected retry";
+ const struct loopinfo *lp = s->loop;
- if (!s->loop) {
+ while (lp && lp->type != LOOP_RESCUE) {
+ lp = lp->prev;
+ }
+ if (!lp) {
raise_error(s, msg);
}
else {
- struct loopinfo *lp = s->loop;
- int n = 0;
-
- while (lp && lp->type != LOOP_RESCUE) {
- if (lp->type == LOOP_BEGIN) {
- n++;
- }
- lp = lp->prev;
- }
- if (!lp) {
- raise_error(s, msg);
- }
- else {
- if (n > 0) {
- genop_1(s, OP_POPERR, n);
- }
- if (s->ensure_level > lp->ensure_level) {
- genop_1(s, OP_EPOP, s->ensure_level - lp->ensure_level);
- }
- genjmp(s, OP_JMP, lp->pc0);
- }
+ genjmp(s, OP_JMPUW, lp->pc0);
}
if (val) push();
}
@@ -2264,26 +2461,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));
@@ -2320,19 +2516,11 @@ 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[3];
- int sym;
+ char buf[] = {'$', nchar(tree)};
+ int sym = new_sym(s, mrb_intern(s->mrb, buf, sizeof(buf)));
- buf[0] = '$';
- buf[1] = nchar(tree);
- buf[2] = 0;
- sym = new_sym(s, mrb_intern_cstr(s->mrb, buf));
genop_2(s, OP_GETGV, cursp(), sym);
push();
}
@@ -2344,7 +2532,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();
@@ -2366,23 +2554,27 @@ codegen(codegen_scope *s, node *tree, int val)
mrb_int i;
mrb_bool overflow;
- i = readint_mrb_int(s, p, base, FALSE, &overflow);
-#ifndef MRB_WITHOUT_FLOAT
+ i = readint(s, p, base, &overflow);
if (overflow) {
- double f = readint_float(s, p, base);
- int off = new_lit(s, mrb_float_value(s->mrb, f));
-
+ int off = new_litbn(s, p, base, FALSE);
genop_2(s, OP_LOADL, cursp(), off);
}
- 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);
+ else {
+ 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 >= INT16_MIN) genop_2S(s, OP_LOADI16, cursp(), (uint16_t)i);
+ else if (i >= INT32_MIN) genop_2SS(s, OP_LOADI32, cursp(), (uint32_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 <= INT16_MAX) genop_2S(s, OP_LOADI16, cursp(), (uint16_t)i);
+ else if (i <= INT32_MAX) genop_2SS(s, OP_LOADI32, cursp(), (uint32_t)i);
else {
- int off = new_lit(s, mrb_fixnum_value(i));
+ int off;
+ lit_int:
+ off = new_lit(s, mrb_int_value(s->mrb, i));
genop_2(s, OP_LOADL, cursp(), off);
}
}
@@ -2390,7 +2582,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
break;
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
case NODE_FLOAT:
if (val) {
char *p = (char*)tree;
@@ -2407,7 +2599,7 @@ codegen(codegen_scope *s, node *tree, int val)
{
nt = nint(tree->car);
switch (nt) {
-#ifndef MRB_WITHOUT_FLOAT
+#ifndef MRB_NO_FLOAT
case NODE_FLOAT:
if (val) {
char *p = (char*)tree->cdr;
@@ -2427,34 +2619,35 @@ codegen(codegen_scope *s, node *tree, int val)
mrb_int i;
mrb_bool overflow;
- i = readint_mrb_int(s, p, base, TRUE, &overflow);
-#ifndef MRB_WITHOUT_FLOAT
+ i = readint(s, p, base, &overflow);
if (overflow) {
- double f = readint_float(s, p, base);
- int off = new_lit(s, mrb_float_value(s->mrb, -f));
-
+ int off = new_litbn(s, p, base, TRUE);
genop_2(s, OP_LOADL, cursp(), off);
}
else {
-#endif
+ i = -i;
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 >= INT16_MIN) {
+ genop_2S(s, OP_LOADI16, cursp(), (uint16_t)i);
+ }
+ else if (i >= INT32_MIN) {
+ genop_2SS(s, OP_LOADI32, cursp(), (uint32_t)i);
+ }
else {
- int off = new_lit(s, mrb_fixnum_value(i));
+ int off = new_lit(s, mrb_int_value(s->mrb, i));
genop_2(s, OP_LOADL, cursp(), off);
}
-#ifndef MRB_WITHOUT_FLOAT
}
-#endif
push();
}
break;
default:
if (val) {
- int sym = new_sym(s, mrb_intern_lit(s->mrb, "-@"));
+ int sym = new_sym(s, MRB_OPSYM_2(s->mrb, minus));
codegen(s, tree, VAL);
pop();
genop_3(s, OP_SEND, cursp(), sym, 0);
@@ -2527,7 +2720,7 @@ codegen(codegen_scope *s, node *tree, int val)
{
node *n;
int ai = mrb_gc_arena_save(s->mrb);
- int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
+ int sym = new_sym(s, MRB_SYM_2(s->mrb, Kernel));
genop_1(s, OP_LOADSELF, cursp());
push();
@@ -2546,7 +2739,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
push(); /* for block */
pop_n(3);
- sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
+ sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */
genop_3(s, OP_SEND, cursp(), sym, 1);
if (val) push();
mrb_gc_arena_restore(s->mrb, ai);
@@ -2566,7 +2759,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop_2(s, OP_STRING, cursp(), off);
push(); push();
pop_n(3);
- sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
+ sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */
genop_3(s, OP_SEND, cursp(), sym, 1);
if (val) push();
mrb_gc_arena_restore(s->mrb, ai);
@@ -2607,7 +2800,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
push(); /* space for a block */
pop_n(argc+2);
- sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
+ sym = new_sym(s, MRB_SYM_2(s->mrb, compile));
genop_3(s, OP_SEND, cursp(), sym, argc);
mrb_gc_arena_restore(s->mrb, ai);
push();
@@ -2661,7 +2854,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
push(); /* space for a block */
pop_n(argc+2);
- sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
+ sym = new_sym(s, MRB_SYM_2(s->mrb, compile));
genop_3(s, OP_SEND, cursp(), sym, argc);
mrb_gc_arena_restore(s->mrb, ai);
push();
@@ -2778,7 +2971,10 @@ codegen(codegen_scope *s, node *tree, int val)
idx = new_sym(s, nsym(tree->car->cdr));
genop_2(s, OP_CLASS, cursp(), idx);
body = tree->cdr->cdr->car;
- if (!(nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL)) {
+ if (nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL) {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ else {
idx = scope_body(s, body, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
@@ -2806,8 +3002,11 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
idx = new_sym(s, nsym(tree->car->cdr));
genop_2(s, OP_MODULE, cursp(), idx);
- if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
- tree->cdr->car->cdr->cdr == NULL)) {
+ if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+ tree->cdr->car->cdr->cdr == NULL) {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ else {
idx = scope_body(s, tree->cdr->car, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
@@ -2824,8 +3023,11 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
genop_1(s, OP_SCLASS, cursp());
- if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
- tree->cdr->car->cdr->cdr == NULL)) {
+ if (nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+ tree->cdr->car->cdr->cdr == NULL) {
+ genop_1(s, OP_LOADNIL, cursp());
+ }
+ else {
idx = scope_body(s, tree->cdr->car, val);
genop_2(s, OP_EXEC, cursp(), idx);
}
@@ -2846,10 +3048,7 @@ codegen(codegen_scope *s, node *tree, int val)
push(); pop();
pop();
genop_2(s, OP_DEF, cursp(), sym);
- if (val) {
- genop_2(s, OP_LOADSYM, cursp(), sym);
- push();
- }
+ if (val) push();
}
break;
@@ -2866,10 +3065,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop_2(s, OP_METHOD, cursp(), idx);
pop();
genop_2(s, OP_DEF, cursp(), sym);
- if (val) {
- genop_2(s, OP_LOADSYM, cursp(), sym);
- push();
- }
+ if (val) push();
}
break;
@@ -2885,97 +3081,100 @@ codegen(codegen_scope *s, node *tree, int val)
}
static void
-scope_add_irep(codegen_scope *s, mrb_irep *irep)
+scope_add_irep(codegen_scope *s)
{
- if (s->irep == NULL) {
- s->irep = irep;
+ mrb_irep *irep;
+ codegen_scope *prev = s->prev;
+
+ if (prev->irep == NULL) {
+ irep = mrb_add_irep(s->mrb);
+ prev->irep = s->irep = irep;
return;
}
- if (s->irep->rlen == s->rcapa) {
- s->rcapa *= 2;
- s->irep->reps = (mrb_irep**)codegen_realloc(s, s->irep->reps, sizeof(mrb_irep*)*s->rcapa);
+ else {
+ if (prev->irep->rlen == UINT16_MAX) {
+ codegen_error(s, "too many nested blocks/methods");
+ }
+ s->irep = irep = mrb_add_irep(s->mrb);
+ if (prev->irep->rlen == prev->rcapa) {
+ prev->rcapa *= 2;
+ prev->reps = (mrb_irep**)codegen_realloc(s, prev->reps, sizeof(mrb_irep*)*prev->rcapa);
+ }
+ prev->reps[prev->irep->rlen] = irep;
+ prev->irep->rlen++;
}
- s->irep->reps[s->irep->rlen] = irep;
- s->irep->rlen++;
}
static codegen_scope*
-scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
+scope_new(mrb_state *mrb, codegen_scope *prev, node *nlv)
{
static const codegen_scope codegen_scope_zero = { 0 };
mrb_pool *pool = mrb_pool_open(mrb);
- codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope));
-
- if (!p) return NULL;
- *p = codegen_scope_zero;
- p->mrb = mrb;
- p->mpool = pool;
- if (!prev) return p;
- p->prev = prev;
- p->ainfo = -1;
- p->mscope = 0;
-
- p->irep = mrb_add_irep(mrb);
- scope_add_irep(prev, p->irep);
-
- p->rcapa = 8;
- p->irep->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*p->rcapa);
-
- p->icapa = 1024;
- p->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*p->icapa);
- p->irep->iseq = NULL;
-
- p->pcapa = 32;
- p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa);
- p->irep->plen = 0;
-
- p->scapa = 256;
- p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa);
- p->irep->slen = 0;
-
- p->lv = lv;
- p->sp += node_len(lv)+1; /* add self */
- p->nlocals = p->sp;
- if (lv) {
- node *n = lv;
+ codegen_scope *s = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope));
+
+ if (!s) {
+ if (prev)
+ codegen_error(prev, "unexpected scope");
+ return NULL;
+ }
+ *s = codegen_scope_zero;
+ s->mrb = mrb;
+ s->mpool = pool;
+ if (!prev) return s;
+ s->prev = prev;
+ s->ainfo = -1;
+ s->mscope = 0;
+
+ scope_add_irep(s);
+
+ s->rcapa = 8;
+ s->reps = (mrb_irep**)mrb_malloc(mrb, sizeof(mrb_irep*)*s->rcapa);
+
+ s->icapa = 1024;
+ s->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*s->icapa);
+
+ s->pcapa = 32;
+ s->pool = (mrb_pool_value*)mrb_malloc(mrb, sizeof(mrb_pool_value)*s->pcapa);
+
+ s->scapa = 256;
+ s->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*s->scapa);
+
+ s->lv = nlv;
+ s->sp += node_len(nlv)+1; /* add self */
+ s->nlocals = s->sp;
+ if (nlv) {
+ mrb_sym *lv;
+ node *n = nlv;
size_t i = 0;
- p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (p->nlocals - 1));
- for (i=0, n=lv; n; i++,n=n->cdr) {
- p->irep->lv[i].name = lv_name(n);
- if (lv_name(n)) {
- p->irep->lv[i].r = lv_idx(p, lv_name(n));
- }
- else {
- p->irep->lv[i].r = 0;
- }
+ s->irep->lv = lv = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*(s->nlocals-1));
+ for (i=0, n=nlv; n; i++,n=n->cdr) {
+ lv[i] = lv_name(n);
}
- mrb_assert(i + 1 == p->nlocals);
+ mrb_assert(i + 1 == s->nlocals);
}
- p->ai = mrb_gc_arena_save(mrb);
+ s->ai = mrb_gc_arena_save(mrb);
- p->filename = prev->filename;
- if (p->filename) {
- p->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*p->icapa);
+ s->filename_sym = prev->filename_sym;
+ if (s->filename_sym) {
+ s->lines = (uint16_t*)mrb_malloc(mrb, sizeof(short)*s->icapa);
}
- p->lineno = prev->lineno;
+ s->lineno = prev->lineno;
/* debug setting */
- p->debug_start_pos = 0;
- if (p->filename) {
- mrb_debug_info_alloc(mrb, p->irep);
- p->irep->filename = p->filename;
- p->irep->lines = p->lines;
+ s->debug_start_pos = 0;
+ if (s->filename_sym) {
+ mrb_debug_info_alloc(mrb, s->irep);
}
else {
- p->irep->debug_info = NULL;
+ s->irep->debug_info = NULL;
}
- p->parser = prev->parser;
- p->filename_index = prev->filename_index;
+ s->parser = prev->parser;
+ s->filename_index = prev->filename_index;
- p->rlev = prev->rlev+1;
+ s->rlev = prev->rlev+1;
- return p;
+ return s;
}
static void
@@ -2983,34 +3182,35 @@ scope_finish(codegen_scope *s)
{
mrb_state *mrb = s->mrb;
mrb_irep *irep = s->irep;
- size_t fname_len;
- char *fname;
+ if (s->nlocals > 0xff) {
+ 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);
+ size_t catchsize = sizeof(struct mrb_irep_catch_handler) * irep->clen;
+ irep->iseq = (const mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc + catchsize);
irep->ilen = s->pc;
- if (s->lines) {
- irep->lines = (uint16_t *)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->pc);
- }
- else {
- irep->lines = 0;
+ if (irep->clen > 0) {
+ memcpy((void *)(irep->iseq + irep->ilen), s->catch_table, catchsize);
}
}
- irep->pool = (mrb_value*)codegen_realloc(s, irep->pool, sizeof(mrb_value)*irep->plen);
- irep->syms = (mrb_sym*)codegen_realloc(s, irep->syms, sizeof(mrb_sym)*irep->slen);
- irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen);
- if (s->filename) {
- irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
- mrb_debug_info_append_file(mrb, irep, s->debug_start_pos, s->pc);
+ else {
+ irep->clen = 0;
+ }
+ mrb_free(s->mrb, s->catch_table);
+ s->catch_table = NULL;
+ irep->pool = (const mrb_pool_value*)codegen_realloc(s, s->pool, sizeof(mrb_pool_value)*irep->plen);
+ irep->syms = (const mrb_sym*)codegen_realloc(s, s->syms, sizeof(mrb_sym)*irep->slen);
+ irep->reps = (const mrb_irep**)codegen_realloc(s, s->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_sym_name_len(s->mrb, fname, NULL);
- fname_len = strlen(s->filename);
- fname = (char*)codegen_malloc(s, fname_len + 1);
- memcpy(fname, s->filename, fname_len);
- fname[fname_len] = '\0';
- irep->filename = fname;
- irep->own_filename = TRUE;
+ mrb_debug_info_append_file(s->mrb, s->irep->debug_info,
+ filename, s->lines, s->debug_start_pos, s->pc);
}
+ mrb_free(s->mrb, s->lines);
irep->nlocals = s->nlocals;
irep->nregs = s->nregs;
@@ -3025,9 +3225,8 @@ loop_push(codegen_scope *s, enum looptype t)
struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo));
p->type = t;
- p->pc0 = p->pc1 = p->pc2 = p->pc3 = 0;
+ p->pc0 = p->pc1 = p->pc2 = p->pc3 = JMPLINK_START;
p->prev = s->loop;
- p->ensure_level = s->ensure_level;
p->acc = cursp();
s->loop = p;
@@ -3043,7 +3242,6 @@ loop_break(codegen_scope *s, node *tree)
}
else {
struct loopinfo *loop;
- int n = 0;
if (tree) {
gen_retval(s, tree);
@@ -3052,7 +3250,6 @@ loop_break(codegen_scope *s, node *tree)
loop = s->loop;
while (loop) {
if (loop->type == LOOP_BEGIN) {
- n++;
loop = loop->prev;
}
else if (loop->type == LOOP_RESCUE) {
@@ -3066,20 +3263,14 @@ loop_break(codegen_scope *s, node *tree)
raise_error(s, "unexpected break");
return;
}
- if (n > 0) {
- genop_1(s, OP_POPERR, n);
- }
if (loop->type == LOOP_NORMAL) {
int tmp;
- if (s->ensure_level > s->loop->ensure_level) {
- genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
- }
if (tree) {
gen_move(s, loop->acc, cursp(), 0);
}
- tmp = genjmp(s, OP_JMP, loop->pc3);
+ tmp = genjmp(s, OP_JMPUW, loop->pc3);
loop->pc3 = tmp;
}
else {
@@ -3102,6 +3293,28 @@ loop_pop(codegen_scope *s, int val)
if (val) push();
}
+static int
+catch_handler_new(codegen_scope *s)
+{
+ size_t newsize = sizeof(struct mrb_irep_catch_handler) * (s->irep->clen + 1);
+ s->catch_table = (struct mrb_irep_catch_handler *)codegen_realloc(s, (void *)s->catch_table, newsize);
+ return s->irep->clen ++;
+}
+
+static void
+catch_handler_set(codegen_scope *s, int ent, enum mrb_catch_type type, uint32_t begin, uint32_t end, uint32_t target)
+{
+ struct mrb_irep_catch_handler *e;
+
+ mrb_assert(ent >= 0 && ent < s->irep->clen);
+
+ e = &s->catch_table[ent];
+ uint8_to_bin(type, &e->type);
+ mrb_irep_catch_handler_pack(begin, e->begin);
+ mrb_irep_catch_handler_pack(end, e->end);
+ mrb_irep_catch_handler_pack(target, e->target);
+}
+
static struct RProc*
generate_code(mrb_state *mrb, parser_state *p, int val)
{
@@ -3109,12 +3322,9 @@ 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 = p->filename;
+ scope->filename_sym = p->filename_sym;
scope->filename_index = p->current_filename_index;
MRB_TRY(&scope->jmp) {
@@ -3151,13 +3361,14 @@ mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep)
{
int i;
+ if (irep->flags & MRB_IREP_NO_FREE) return;
if (irep->lv) {
- mrb_free(mrb, irep->lv);
+ mrb_free(mrb, (void*)irep->lv);
irep->lv = NULL;
}
-
+ if (!irep->reps) return;
for (i = 0; i < irep->rlen; ++i) {
- mrb_irep_remove_lv(mrb, irep->reps[i]);
+ mrb_irep_remove_lv(mrb, (mrb_irep*)irep->reps[i]);
}
}
@@ -3165,21 +3376,20 @@ mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep)
#define Z 1
#define S 3
#define W 4
+#define OPCODE(_,x) x,
/* instruction sizes */
uint8_t mrb_insn_size[] = {
#define B 2
#define BB 3
#define BBB 4
#define BS 4
-#define SB 4
-#define OPCODE(_,x) x,
+#define BSS 6
#include "mruby/ops.h"
-#undef OPCODE
#undef B
#undef BB
-#undef BS
-#undef SB
#undef BBB
+#undef BS
+#undef BSS
};
/* EXT1 instruction sizes */
uint8_t mrb_insn_size1[] = {
@@ -3187,29 +3397,30 @@ uint8_t mrb_insn_size1[] = {
#define BB 4
#define BBB 5
#define BS 5
-#define SB 5
-#define OPCODE(_,x) x,
+#define BSS 7
#include "mruby/ops.h"
-#undef OPCODE
#undef B
+#undef BS
+#undef BSS
};
/* EXT2 instruction sizes */
uint8_t mrb_insn_size2[] = {
#define B 2
-#define OPCODE(_,x) x,
+#define BS 4
+#define BSS 6
#include "mruby/ops.h"
-#undef OPCODE
+#undef B
#undef BB
#undef BBB
#undef BS
-#undef SB
+#undef BSS
};
/* EXT3 instruction sizes */
+#define B 3
#define BB 5
#define BBB 6
-#define BS 4
-#define SB 5
+#define BS 5
+#define BSS 7
uint8_t mrb_insn_size3[] = {
-#define OPCODE(_,x) x,
#include "mruby/ops.h"
};