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 {
#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)
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();
if (no_peephole(s)) {
normal:
genop_2(s, OP_MOVE, dst, src);
- if (on_eval(s)) {
- genop_0(s, OP_NOP);
- }
return;
}
else {
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;
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;
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
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)
{
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 */
{
codegen_scope *parent = s;
s = scope_new(s->mrb, s, tree->car);
- if (s == NULL) {
- raise_error(parent, "unexpected scope");
- }
s->mscope = !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);
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;
}
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);
}
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);
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 /* '=' */
}
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();
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());
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);
}
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);
case NODE_IF:
{
- int pos1, pos2;
+ int pos1, pos2, nil_p = FALSE;
node *elsepart = tree->cdr->cdr->car;
if (!tree->car) {
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;
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);
{
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] == '|') &&
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));
}
break;
- case NODE_DEFINED:
- codegen(s, tree, val);
- break;
-
case NODE_BACK_REF:
if (val) {
char buf[] = {'$', nchar(tree)};
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();
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);
}
}
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);
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;
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);
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);
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;