diff options
Diffstat (limited to 'mrbgems/mruby-compiler/core/codegen.c')
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 1204 |
1 files changed, 821 insertions, 383 deletions
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 12f7c3b3f..42c93debf 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -4,10 +4,6 @@ ** See Copyright Notice in mruby.h */ -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> #include <mruby.h> #include <mruby/compile.h> #include <mruby/proc.h> @@ -20,6 +16,8 @@ #include <mruby/opcode.h> #include <mruby/re.h> #include <mruby/throw.h> +#include <ctype.h> +#include <string.h> #ifndef MRB_CODEGEN_LEVEL_MAX #define MRB_CODEGEN_LEVEL_MAX 1024 @@ -40,15 +38,16 @@ enum looptype { struct loopinfo { enum looptype type; - uint32_t pc0, pc1, pc2, pc3; - int acc; + uint32_t pc0; /* `next` destination */ + uint32_t pc1; /* `redo` destination */ + uint32_t pc2; /* `break` destination */ + int reg; /* destination register */ struct loopinfo *prev; }; typedef struct scope { mrb_state *mrb; mrb_pool *mpool; - struct mrb_jmpbuf jmp; struct scope *prev; @@ -147,7 +146,7 @@ codegen_error(codegen_scope *s, const char *message) fprintf(stderr, "%s\n", message); } #endif - MRB_THROW(&s->jmp); + MRB_THROW(s->mrb->jmp); } static void* @@ -237,7 +236,9 @@ genop_1(codegen_scope *s, mrb_code i, uint16_t a) { s->lastpc = s->pc; if (a > 0xff) { - codegen_error(s, "too big operand"); + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); } else { gen_B(s, i); @@ -249,30 +250,24 @@ static void genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) { s->lastpc = s->pc; - if (a > 0xff || b > 0xff) { - codegen_error(s, "too big operand"); - } - else { + if (a > 0xff && b > 0xff) { + gen_B(s, OP_EXT3); gen_B(s, i); - gen_B(s, (uint8_t)a); - gen_B(s, (uint8_t)b); - } -} - -/* similar to `genop_2` but generate `genop_2S` with `i+1` */ -/* works for OP_LOADL, OP_LOADSYM, OP_STRING */ -static void -genop_bs(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b) -{ - s->lastpc = s->pc; - if (a > 0xff || b > 0xffff) { - codegen_error(s, "too big operand"); + gen_S(s, a); + gen_S(s, b); } - if (b > 0xff) { - gen_B(s, i+1); + else if (b > 0xff) { + gen_B(s, OP_EXT2); + gen_B(s, i); gen_B(s, (uint8_t)a); gen_S(s, b); } + else if (a > 0xff) { + gen_B(s, OP_EXT1); + gen_B(s, i); + gen_S(s, a); + gen_B(s, (uint8_t)b); + } else { gen_B(s, i); gen_B(s, (uint8_t)a); @@ -331,6 +326,8 @@ struct mrb_insn_data mrb_decode_insn(const mrb_code *pc) { struct mrb_insn_data data = { 0 }; + if (pc == 0) return data; + data.addr = pc; mrb_code insn = READ_B(); uint16_t a = 0; uint16_t b = 0; @@ -341,6 +338,32 @@ mrb_decode_insn(const mrb_code *pc) #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break; #include "mruby/ops.h" #undef OPCODE + } + switch (insn) { + case OP_EXT1: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT2: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; + case OP_EXT3: + insn = READ_B(); + switch (insn) { +#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break; +#include "mruby/ops.h" +#undef OPCODE + } + break; default: break; } @@ -351,13 +374,101 @@ mrb_decode_insn(const mrb_code *pc) return data; } +#undef OPCODE +#define Z 1 +#define S 3 +#define W 4 +#define OPCODE(_,x) x, +/* instruction sizes */ +static uint8_t mrb_insn_size[] = { +#define B 2 +#define BB 3 +#define BBB 4 +#define BS 4 +#define BSS 6 +#include "mruby/ops.h" +#undef B +#undef BB +#undef BBB +#undef BS +#undef BSS +}; +/* EXT1 instruction sizes */ +static uint8_t mrb_insn_size1[] = { +#define B 3 +#define BB 4 +#define BBB 5 +#define BS 5 +#define BSS 7 +#include "mruby/ops.h" +#undef B +#undef BS +#undef BSS +}; +/* EXT2 instruction sizes */ +static uint8_t mrb_insn_size2[] = { +#define B 2 +#define BS 4 +#define BSS 6 +#include "mruby/ops.h" +#undef B +#undef BB +#undef BBB +#undef BS +#undef BSS +}; +/* EXT3 instruction sizes */ +#define B 3 +#define BB 5 +#define BBB 6 +#define BS 5 +#define BSS 7 +static uint8_t mrb_insn_size3[] = { +#include "mruby/ops.h" +}; +#undef B +#undef BB +#undef BBB +#undef BS +#undef BSS +#undef OPCODE + +static const mrb_code* +mrb_prev_pc(codegen_scope *s, const mrb_code *pc) +{ + const mrb_code *prev_pc = NULL; + const mrb_code *i = s->iseq; + + while (i<pc) { + uint8_t insn = i[0]; + prev_pc = i; + switch (insn) { + case OP_EXT1: + i += mrb_insn_size1[i[1]] + 1; + break; + case OP_EXT2: + i += mrb_insn_size2[i[1]] + 1; + break; + case OP_EXT3: + i += mrb_insn_size3[i[1]] + 1; + break; + default: + i += mrb_insn_size[insn]; + break; + } + } + return prev_pc; +} + +#define pc_addr(s) &((s)->iseq[(s)->pc]) +#define addr_pc(s, addr) (uint32_t)((addr) - s->iseq) +#define rewind_pc(s) s->pc = s->lastpc + static struct mrb_insn_data mrb_last_insn(codegen_scope *s) { - if (s->pc == s->lastpc) { - struct mrb_insn_data data; - - data.insn = OP_NOP; + if (s->pc == 0) { + struct mrb_insn_data data = { OP_NOP, 0 }; return data; } return mrb_decode_insn(&s->iseq[s->lastpc]); @@ -376,17 +487,15 @@ gen_jmpdst(codegen_scope *s, uint32_t pc) { if (pc == JMPLINK_START) { - gen_S(s, 0); + pc = 0; } - else { - uint32_t pos2 = s->pc+2; - int32_t off = pc - pos2; + 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); + if (off > INT16_MAX || INT16_MIN > off) { + codegen_error(s, "too big jump offset"); } + gen_S(s, (uint16_t)off); } static uint32_t @@ -394,8 +503,7 @@ genjmp(codegen_scope *s, mrb_code i, uint32_t pc) { uint32_t pos; - s->lastpc = s->pc; - gen_B(s, i); + genop_0(s, i); pos = s->pc; gen_jmpdst(s, pc); return pos; @@ -411,36 +519,64 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, uint32_t pc, int val) if (!no_peephole(s) && !val) { struct mrb_insn_data data = mrb_last_insn(s); - if (data.insn == OP_MOVE && data.a == a) { - s->pc = s->lastpc; - a = data.b; + switch (data.insn) { + case OP_MOVE: + if (data.a == a && data.a > s->nlocals) { + rewind_pc(s); + a = data.b; + } + break; + case OP_LOADNIL: + case OP_LOADF: + if (data.a == a || data.a > s->nlocals) { + s->pc = addr_pc(s, data.addr); + if (i == OP_JMPNOT || (i == OP_JMPNIL && data.insn == OP_LOADNIL)) { + return genjmp(s, OP_JMP, pc); + } + else { /* OP_JMPIF */ + return JMPLINK_START; + } + } + break; + case OP_LOADT: case OP_LOADI: case OP_LOADINEG: case OP_LOADI__1: + case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: + case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: + if (data.a == a || data.a > s->nlocals) { + s->pc = addr_pc(s, data.addr); + if (i == OP_JMPIF) { + return genjmp(s, OP_JMP, pc); + } + else { /* OP_JMPNOT and OP_JMPNIL */ + return JMPLINK_START; + } + } + break; } } - s->lastpc = s->pc; if (a > 0xff) { - codegen_error(s, "too big operand"); - pos = 0; + gen_B(s, OP_EXT1); + genop_0(s, i); + gen_S(s, a); } else { - gen_B(s, i); + genop_0(s, i); gen_B(s, (uint8_t)a); - pos = s->pc; - gen_jmpdst(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 mrb_bool get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *ns); +static void gen_int(codegen_scope *s, uint16_t dst, mrb_int i); + 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); - return; - } + if (nopeep || no_peephole(s)) goto normal; else { struct mrb_insn_data data = mrb_last_insn(s); @@ -454,25 +590,100 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) case OP_LOADI__1: case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: - if (nopeep || data.a != src || data.a < s->nlocals) goto normal; - s->pc = s->lastpc; + if (data.a != src || data.a < s->nlocals) goto normal; + rewind_pc(s); genop_1(s, data.insn, dst); - break; + return; case OP_LOADI: case OP_LOADINEG: case OP_LOADL: case OP_LOADSYM: - case OP_LOADL16: case OP_LOADSYM16: case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV: - case OP_GETCONST: case OP_STRING: case OP_STRING16: + case OP_GETCONST: case OP_STRING: case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH: - case OP_LAMBDA16: case OP_BLOCK16: case OP_METHOD16: - if (nopeep || data.a != src || data.a < s->nlocals) goto normal; - s->pc = s->lastpc; + if (data.a != src || data.a < s->nlocals) goto normal; + rewind_pc(s); genop_2(s, data.insn, dst, data.b); - break; + return; + case OP_LOADI16: + if (data.a != src || data.a < s->nlocals) goto normal; + rewind_pc(s); + genop_2S(s, data.insn, dst, data.b); + return; + case OP_LOADI32: + if (data.a != src || data.a < s->nlocals) goto normal; + else { + uint32_t i = (uint32_t)data.b<<16|data.c; + rewind_pc(s); + genop_2SS(s, data.insn, dst, i); + } + return; + case OP_GETUPVAR: + if (data.a != src || data.a < s->nlocals) goto normal; + rewind_pc(s); + genop_3(s, data.insn, dst, data.b, data.c); + return; + case OP_ADDI: case OP_SUBI: + if (addr_pc(s, data.addr) == s->lastlabel || data.a != src || data.a < s->nlocals) goto normal; + else { + struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); + if (data0.insn != OP_MOVE || data0.a != data.a || data0.b != dst) goto normal; + s->pc = addr_pc(s, data0.addr); + if (addr_pc(s, data0.addr) != s->lastlabel) { + /* constant folding */ + data0 = mrb_decode_insn(mrb_prev_pc(s, data0.addr)); + mrb_int n; + if (data0.a == dst && get_int_operand(s, &data0, &n)) { + if ((data.insn == OP_ADDI && !mrb_int_add_overflow(n, data.b, &n)) || + (data.insn == OP_SUBI && !mrb_int_sub_overflow(n, data.b, &n))) { + s->pc = addr_pc(s, data0.addr); + gen_int(s, dst, n); + return; + } + } + } + } + genop_2(s, data.insn, dst, data.b); + return; default: - goto normal; + break; + } + } + normal: + genop_2(s, OP_MOVE, dst, src); + return; +} + +static int search_upvar(codegen_scope *s, mrb_sym id, int *idx); + +static void +gen_getupvar(codegen_scope *s, uint16_t dst, mrb_sym id) +{ + int idx; + int lv = search_upvar(s, id, &idx); + + if (!no_peephole(s)) { + struct mrb_insn_data data = mrb_last_insn(s); + if (data.insn == OP_SETUPVAR && data.a == dst && data.b == idx && data.c == lv) { + /* skip GETUPVAR right after SETUPVAR */ + return; + } + } + genop_3(s, OP_GETUPVAR, dst, idx, lv); +} + +static void +gen_setupvar(codegen_scope *s, uint16_t dst, mrb_sym id) +{ + int idx; + int lv = search_upvar(s, id, &idx); + + if (!no_peephole(s)) { + struct mrb_insn_data data = mrb_last_insn(s); + if (data.insn == OP_MOVE && data.a == dst) { + dst = data.b; + rewind_pc(s); } } + genop_3(s, OP_SETUPVAR, dst, idx, lv); } static void @@ -485,7 +696,7 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src) struct mrb_insn_data data = mrb_last_insn(s); if (data.insn == OP_MOVE && src == data.a) { - s->pc = s->lastpc; + rewind_pc(s); genop_1(s, op, data.b); } else if (data.insn != OP_RETURN) { @@ -494,6 +705,55 @@ gen_return(codegen_scope *s, uint8_t op, uint16_t src) } } +static mrb_bool +get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *n) +{ + switch (data->insn) { + case OP_LOADI__1: + *n = -1; + return TRUE; + + case OP_LOADINEG: + *n = -data->b; + return TRUE; + + case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: + case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: + *n = data->insn - OP_LOADI_0; + return TRUE; + + case OP_LOADI: + case OP_LOADI16: + *n = data->b; + return TRUE; + + case OP_LOADI32: + *n = (mrb_int)((uint32_t)data->b<<16)+data->c; + return TRUE; + + case OP_LOADL: + { + mrb_pool_value *pv = &s->pool[data->b]; + + if (pv->tt == IREP_TT_INT32) { + *n = (mrb_int)pv->u.i32; + } +#ifdef MRB_INT64 + else if (pv->tt == IREP_TT_INT64) { + *n = (mrb_int)pv->u.i64; + } +#endif + else { + return FALSE; + } + } + return TRUE; + + default: + return FALSE; + } +} + static void gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) { @@ -504,31 +764,119 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) } else { struct mrb_insn_data data = mrb_last_insn(s); + mrb_int n; - switch (data.insn) { - case OP_LOADI__1: - if (op == OP_ADD) op = OP_SUB; - else op = OP_ADD; - data.b = 1; - goto replace; - case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3: - case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7: - data.b = data.insn - OP_LOADI_0; - /* fall through */ - case OP_LOADI: - replace: - if (data.b >= 128) goto normal; - s->pc = s->lastpc; + if (!get_int_operand(s, &data, &n)) { + /* not integer immediate */ + goto normal; + } + struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); + mrb_int n0; + if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data0, &n0)) { + /* OP_ADDI/OP_SUBI takes upto 16bits */ + if (n > INT16_MAX) goto normal; + rewind_pc(s); if (op == OP_ADD) { - genop_2(s, OP_ADDI, dst, (uint8_t)data.b); + genop_2(s, OP_ADDI, dst, (uint16_t)n); } else { - genop_2(s, OP_SUBI, dst, (uint8_t)data.b); + genop_2(s, OP_SUBI, dst, (uint16_t)n); } - break; - default: + return; + } + if (op == OP_ADD) { + if (mrb_int_add_overflow(n0, n, &n)) goto normal; + } + else { /* OP_SUB */ + if (mrb_int_sub_overflow(n0, n, &n)) goto normal; + } + s->pc = addr_pc(s, data0.addr); + gen_int(s, dst, n); + } +} + +static void +gen_muldiv(codegen_scope *s, uint8_t op, uint16_t dst) +{ + if (no_peephole(s)) { + normal: + genop_1(s, op, dst); + return; + } + else { + struct mrb_insn_data data = mrb_last_insn(s); + mrb_int n, n0; + if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data, &n)) { + /* not integer immediate */ goto normal; } + struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); + if (!get_int_operand(s, &data0, &n0) || n == 0) { + goto normal; + } + if (op == OP_MUL) { + if (mrb_int_mul_overflow(n0, n, &n)) goto normal; + } + else { /* OP_DIV */ + if (n0 == MRB_INT_MIN && n == -1) goto normal; + n = n0 / n; + } + s->pc = addr_pc(s, data0.addr); + gen_int(s, dst, n); + } +} + +mrb_bool mrb_num_shift(mrb_state *mrb, mrb_int val, mrb_int width, mrb_int *num); + +static mrb_bool +gen_binop(codegen_scope *s, mrb_sym op, uint16_t dst) +{ + if (no_peephole(s)) return FALSE; + else { + struct mrb_insn_data data = mrb_last_insn(s); + mrb_int n, n0; + if (addr_pc(s, data.addr) == s->lastlabel || !get_int_operand(s, &data, &n)) { + /* not integer immediate */ + return FALSE; + } + struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr)); + if (!get_int_operand(s, &data0, &n0)) { + return FALSE; + } + if (op == MRB_OPSYM_2(s->mrb, lshift)) { + if (!mrb_num_shift(s->mrb, n0, n, &n)) return FALSE; + } + else if (op == MRB_OPSYM_2(s->mrb, rshift)) { + if (n == MRB_INT_MIN) return FALSE; + if (!mrb_num_shift(s->mrb, n0, -n, &n)) return FALSE; + } + else if (op == MRB_OPSYM_2(s->mrb, mod) && n != 0) { + if (n0 == MRB_INT_MIN && n == -1) { + n = 0; + } + else { + mrb_int n1 = n0 % n; + if ((n0 < 0) != (n < 0) && n1 != 0) { + n1 += n; + } + n = n1; + } + } + else if (op == MRB_OPSYM_2(s->mrb, and)) { + n = n0 & n; + } + else if (op == MRB_OPSYM_2(s->mrb, or)) { + n = n0 | n; + } + else if (op == MRB_OPSYM_2(s->mrb, xor)) { + n = n0 ^ n; + } + else { + return FALSE; + } + s->pc = addr_pc(s, data0.addr); + gen_int(s, dst, n); + return TRUE; } } @@ -751,6 +1099,66 @@ new_sym(codegen_scope *s, mrb_sym sym) return s->irep->slen++; } +static void +gen_setxv(codegen_scope *s, uint8_t op, uint16_t dst, mrb_sym sym, int val) +{ + int idx = new_sym(s, sym); + if (!val && !no_peephole(s)) { + struct mrb_insn_data data = mrb_last_insn(s); + if (data.insn == OP_MOVE && data.a == dst) { + dst = data.b; + rewind_pc(s); + } + } + genop_2(s, op, dst, idx); +} + +static void +gen_int(codegen_scope *s, uint16_t dst, mrb_int i) +{ + if (i < 0) { + if (i == -1) genop_1(s, OP_LOADI__1, dst); + else if (i >= -0xff) genop_2(s, OP_LOADINEG, dst, (uint16_t)-i); + else if (i >= INT16_MIN) genop_2S(s, OP_LOADI16, dst, (uint16_t)i); + else if (i >= INT32_MIN) genop_2SS(s, OP_LOADI32, dst, (uint32_t)i); + else goto int_lit; + } + else if (i < 8) genop_1(s, OP_LOADI_0 + (uint8_t)i, dst); + else if (i <= 0xff) genop_2(s, OP_LOADI, dst, (uint16_t)i); + else if (i <= INT16_MAX) genop_2S(s, OP_LOADI16, dst, (uint16_t)i); + else if (i <= INT32_MAX) genop_2SS(s, OP_LOADI32, dst, (uint32_t)i); + else { + int_lit: + genop_2(s, OP_LOADL, dst, new_lit(s, mrb_int_value(s->mrb, i))); + } +} + +static mrb_bool +gen_uniop(codegen_scope *s, mrb_sym sym, uint16_t dst) +{ + if (no_peephole(s)) return FALSE; + struct mrb_insn_data data = mrb_last_insn(s); + mrb_int n; + + if (!get_int_operand(s, &data, &n)) return FALSE; + if (sym == MRB_OPSYM_2(s->mrb, plus)) { + /* unary plus does nothing */ + } + else if (sym == MRB_OPSYM_2(s->mrb, minus)) { + if (n == MRB_INT_MIN) return FALSE; + n = -n; + } + else if (sym == MRB_OPSYM_2(s->mrb, neg)) { + n = ~n; + } + else { + return FALSE; + } + s->pc = addr_pc(s, data.addr); + gen_int(s, dst, n); + return TRUE; +} + static int node_len(node *tree) { @@ -807,10 +1215,12 @@ search_upvar(codegen_scope *s, mrb_sym id, int *idx) int i; const mrb_sym *v = ir->lv; - for (i=1; n > 1; n--, v++, i++) { - if (*v == id) { - *idx = i; - return lv - 1; + 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; @@ -848,7 +1258,7 @@ for_body(codegen_scope *s, node *tree) } /* construct loop */ lp = loop_push(s, LOOP_FOR); - lp->pc2 = new_label(s); + lp->pc1 = new_label(s); /* loop body */ codegen(s, tree->cdr->cdr->car, VAL); @@ -883,8 +1293,8 @@ lambda_body(codegen_scope *s, node *tree, int blk) } else { mrb_aspec a; - int ma, oa, ra, pa, ka, kd, ba; - int pos, i; + int ma, oa, ra, pa, ka, kd, ba, i; + uint32_t pos; node *opt; node *margs, *pargs; node *tail; @@ -945,8 +1355,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) gen_move(s, idx, cursp(), 0); } else { - int lv = search_upvar(s, id, &idx); - genop_3(s, OP_GETUPVAR, cursp(), idx, lv); + gen_getupvar(s, cursp(), id); } i++; opt = opt->cdr; @@ -984,8 +1393,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) gen_move(s, idx, cursp(), 0); } else { - int lv = search_upvar(s, kwd_sym, &idx); - genop_3(s, OP_GETUPVAR, cursp(), idx, lv); + gen_getupvar(s, cursp(), kwd_sym); } jmp_def_set = genjmp_0(s, OP_JMP); dispatch(s, jmpif_key_p); @@ -1092,68 +1500,70 @@ attrsym(codegen_scope *s, mrb_sym a) } #define CALL_MAXARGS 127 +#define GEN_LIT_ARY_MAX 64 +#define GEN_VAL_STACK_MAX 99 static int -gen_values(codegen_scope *s, node *t, int val, int extra) +gen_values(codegen_scope *s, node *t, int val, int extra, int limit) { int n = 0; - int is_splat; + int first = 1; + int slimit = GEN_VAL_STACK_MAX; + + if (limit == 0) limit = GEN_LIT_ARY_MAX; + if (cursp() >= slimit) slimit = INT16_MAX; + + if (!val) { + while (t) { + codegen(s, t->car, NOVAL); + n++; + t = t->cdr; + } + return n; + } while (t) { - is_splat = nint(t->car->car) == NODE_SPLAT; /* splat mode */ - if ( - n+extra >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */ - || is_splat) { - if (val) { - if (is_splat && n == 0 && nint(t->car->cdr->car) == NODE_ARRAY) { - codegen(s, t->car->cdr, VAL); - pop(); + int is_splat = nint(t->car->car) == NODE_SPLAT; + + if (is_splat || n+extra >= limit-1 || cursp() >= slimit) { /* flush stack */ + pop_n(n); + if (first) { + if (n == 0) { + genop_1(s, OP_LOADNIL, cursp()); } else { - pop_n(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(); - if (is_splat) { - genop_1(s, OP_ARYCAT, cursp()); - } - else { - genop_1(s, OP_ARYPUSH, cursp()); - } - } - t = t->cdr; - while (t) { - push(); - codegen(s, t->car, VAL); - pop(); pop(); - if (nint(t->car->car) == NODE_SPLAT) { - genop_1(s, OP_ARYCAT, cursp()); - } - else { - genop_1(s, OP_ARYPUSH, cursp()); - } - t = t->cdr; + genop_2(s, OP_ARRAY, cursp(), n); } + push(); + first = 0; + limit = GEN_LIT_ARY_MAX; } - else { - while (t) { - codegen(s, t->car, NOVAL); - t = t->cdr; - } + else if (n > 0) { + pop(); + genop_2(s, OP_ARYPUSH, cursp(), n); + push(); } - return -1; + n = 0; } - /* normal (no splat) mode */ codegen(s, t->car, val); - n++; + if (is_splat) { + pop(); pop(); + genop_1(s, OP_ARYCAT, cursp()); + push(); + } + else { + n++; + } t = t->cdr; } + if (!first) { + pop(); + if (n > 0) { + pop_n(n); + genop_2(s, OP_ARYPUSH, cursp(), n); + } + return -1; /* variable length */ + } return n; } @@ -1172,7 +1582,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) } tree = tree->cdr->cdr->car; if (tree) { - n = gen_values(s, tree->car, VAL, sp?1:0); + n = gen_values(s, tree->car, VAL, sp?1:0, 14); if (n < 0) { n = noop = sendv = 1; push(); @@ -1182,7 +1592,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) if (sendv) { gen_move(s, cursp(), sp, 0); pop(); - genop_1(s, OP_ARYPUSH, cursp()); + genop_2(s, OP_ARYPUSH, cursp(), 1); push(); } else { @@ -1199,46 +1609,47 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) } push();pop(); pop_n(n+1); - { - mrb_int symlen; - const char *symname = mrb_sym_name_len(s->mrb, sym, &symlen); + if (!noop && sym == MRB_OPSYM_2(s->mrb, add) && n == 1) { + gen_addsub(s, OP_ADD, cursp()); + } + else if (!noop && sym == MRB_OPSYM_2(s->mrb, sub) && n == 1) { + gen_addsub(s, OP_SUB, cursp()); + } + else if (!noop && sym == MRB_OPSYM_2(s->mrb, mul) && n == 1) { + gen_muldiv(s, OP_MUL, cursp()); + } + else if (!noop && sym == MRB_OPSYM_2(s->mrb, div) && n == 1) { + gen_muldiv(s, OP_DIV, cursp()); + } + else if (!noop && sym == MRB_OPSYM_2(s->mrb, lt) && n == 1) { + genop_1(s, OP_LT, cursp()); + } + else if (!noop && sym == MRB_OPSYM_2(s->mrb, le) && n == 1) { + genop_1(s, OP_LE, cursp()); + } + else if (!noop && sym == MRB_OPSYM_2(s->mrb, gt) && n == 1) { + genop_1(s, OP_GT, cursp()); + } + else if (!noop && sym == MRB_OPSYM_2(s->mrb, ge) && n == 1) { + genop_1(s, OP_GE, cursp()); + } + else if (!noop && sym == MRB_OPSYM_2(s->mrb, eq) && n == 1) { + genop_1(s, OP_EQ, cursp()); + } + else if (!noop && n == 0 && gen_uniop(s, sym, cursp())) { + /* constant folding succeeded */ + } + else if (!noop && n == 1 && gen_binop(s, sym, cursp())) { + /* constant folding succeeded */ + } + else { + int idx = new_sym(s, sym); - if (!noop && symlen == 1 && symname[0] == '+' && n == 1) { - gen_addsub(s, OP_ADD, cursp()); - } - else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) { - gen_addsub(s, OP_SUB, cursp()); - } - else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) { - genop_1(s, OP_MUL, cursp()); - } - else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) { - genop_1(s, OP_DIV, cursp()); - } - else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) { - genop_1(s, OP_LT, cursp()); - } - else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) { - genop_1(s, OP_LE, cursp()); - } - else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) { - genop_1(s, OP_GT, cursp()); - } - else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) { - genop_1(s, OP_GE, cursp()); - } - else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) { - genop_1(s, OP_EQ, cursp()); + if (sendv) { + genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx); } else { - int idx = new_sym(s, sym); - - if (sendv) { - genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx); - } - else { - genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), idx, n); - } + genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), idx, n); } } if (safe) { @@ -1258,8 +1669,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) tree = tree->cdr; switch (type) { case NODE_GVAR: - idx = new_sym(s, nsym(tree)); - genop_2(s, OP_SETGV, sp, idx); + gen_setxv(s, OP_SETGV, sp, nsym(tree), val); break; case NODE_ARG: case NODE_LVAR: @@ -1271,8 +1681,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) break; } else { /* upvar */ - int lv = search_upvar(s, nsym(tree), &idx); - genop_3(s, OP_SETUPVAR, sp, idx, lv); + gen_setupvar(s, sp, nsym(tree)); } break; case NODE_NVAR: @@ -1280,16 +1689,13 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) 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); + gen_setxv(s, OP_SETIV, sp, nsym(tree), val); break; case NODE_CVAR: - idx = new_sym(s, nsym(tree)); - genop_2(s, OP_SETCV, sp, idx); + gen_setxv(s, OP_SETCV, sp, nsym(tree), val); break; case NODE_CONST: - idx = new_sym(s, nsym(tree)); - genop_2(s, OP_SETCONST, sp, idx); + gen_setxv(s, OP_SETCONST, sp, nsym(tree), val); break; case NODE_COLON2: gen_move(s, cursp(), sp, 0); @@ -1320,9 +1726,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) break; default: -#ifndef MRB_NO_STDIO - fprintf(stderr, "unknown lhs %d\n", type); -#endif + codegen_error(s, "unknown lhs"); break; } if (val) push(); @@ -1383,6 +1787,16 @@ static void gen_intern(codegen_scope *s) { pop(); + if (!no_peephole(s)) { + struct mrb_insn_data data = mrb_last_insn(s); + + if (data.insn == OP_STRING && data.a == cursp()) { + rewind_pc(s); + genop_2(s, OP_SYMBOL, data.a, data.b); + push(); + return; + } + } genop_1(s, OP_INTERN, cursp()); push(); } @@ -1391,7 +1805,7 @@ static void gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) { if (val) { - int i = 0, j = 0; + int i = 0, j = 0, gen = 0; while (tree) { switch (nint(tree->car->car)) { @@ -1419,6 +1833,19 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) push(); j--; } + if (i > GEN_LIT_ARY_MAX) { + pop_n(i); + if (gen) { + pop(); + genop_2(s, OP_ARYPUSH, cursp(), i); + } + else { + genop_2(s, OP_ARRAY, cursp(), i); + gen = 1; + } + push(); + i = 0; + } tree = tree->cdr; } if (j > 0) { @@ -1427,7 +1854,13 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) gen_intern(s); } pop_n(i); - genop_2(s, OP_ARRAY, cursp(), i); + if (gen) { + pop(); + genop_2(s, OP_ARYPUSH, cursp(), i); + } + else { + genop_2(s, OP_ARRAY, cursp(), i); + } push(); } else { @@ -1450,45 +1883,48 @@ raise_error(codegen_scope *s, const char *msg) } 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 neg, mrb_bool *overflow) { const char *e = p + strlen(p); mrb_int result = 0; - int n; - mrb_assert(base >= 2 && base <= 36); + mrb_assert(base >= 2 && base <= 16); 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"); - } - - 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; - } + *overflow = TRUE; + /* not reached */ + return result; + } + if (mrb_int_mul_overflow(result, base, &result)) { + overflow: + *overflow = TRUE; + return 0; + } + mrb_uint tmp = ((mrb_uint)result)+n; + if (neg && tmp == (mrb_uint)MRB_INT_MAX+1) { + *overflow = FALSE; + return MRB_INT_MIN; + } + if (tmp > MRB_INT_MAX) goto overflow; + result = (mrb_int)tmp; p++; } *overflow = FALSE; + if (neg) return -result; return result; } @@ -1506,6 +1942,32 @@ gen_retval(codegen_scope *s, node *tree) } } +static mrb_bool +true_always(node *tree) +{ + switch (nint(tree->car)) { + case NODE_TRUE: + case NODE_INT: + case NODE_STR: + case NODE_SYM: + return TRUE; + default: + return FALSE; + } +} + +static mrb_bool +false_always(node *tree) +{ + switch (nint(tree->car)) { + case NODE_FALSE: + case NODE_NIL: + return TRUE; + default: + return FALSE; + } +} + static void codegen(codegen_scope *s, node *tree, int val) { @@ -1673,7 +2135,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int idx = lambda_body(s, tree, 1); - genop_bs(s, OP_LAMBDA, cursp(), idx); + genop_2(s, OP_LAMBDA, cursp(), idx); push(); } break; @@ -1682,41 +2144,37 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int idx = lambda_body(s, tree, 1); - genop_bs(s, OP_BLOCK, cursp(), idx); + genop_2(s, OP_BLOCK, cursp(), idx); push(); } break; case NODE_IF: { - int pos1, pos2, nil_p = FALSE; + uint32_t pos1, pos2; + mrb_bool nil_p = FALSE; node *elsepart = tree->cdr->cdr->car; if (!tree->car) { codegen(s, elsepart, val); goto exit; } - switch (nint(tree->car->car)) { - case NODE_TRUE: - case NODE_INT: - case NODE_STR: + if (true_always(tree->car)) { codegen(s, tree->cdr->car, val); goto exit; - case NODE_FALSE: - case NODE_NIL: + } + if (false_always(tree->car)) { 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); - } + } + if (nint(tree->car->car) == NODE_CALL) { + node *n = tree->car->cdr; + mrb_sym mid = nsym(n->cdr->car); + mrb_sym sym_nil_p = MRB_SYM_Q_2(s->mrb, nil); + if (mid == sym_nil_p && n->cdr->cdr->car == NULL) { + nil_p = TRUE; + codegen(s, n->car, VAL); } - break; } if (!nil_p) { codegen(s, tree->car, VAL); @@ -1764,8 +2222,16 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_AND: { - int pos; + uint32_t pos; + if (true_always(tree->car)) { + codegen(s, tree->cdr, val); + goto exit; + } + if (false_always(tree->car)) { + codegen(s, tree->car, val); + goto exit; + } codegen(s, tree->car, VAL); pop(); pos = genjmp2_0(s, OP_JMPNOT, cursp(), val); @@ -1776,8 +2242,16 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_OR: { - int pos; + uint32_t pos; + if (true_always(tree->car)) { + codegen(s, tree->car, val); + goto exit; + } + if (false_always(tree->car)) { + codegen(s, tree->cdr, val); + goto exit; + } codegen(s, tree->car, VAL); pop(); pos = genjmp2_0(s, OP_JMPIF, cursp(), val); @@ -1787,35 +2261,44 @@ codegen(codegen_scope *s, node *tree, int val) break; case NODE_WHILE: - { - struct loopinfo *lp = loop_push(s, LOOP_NORMAL); - - lp->pc0 = new_label(s); - lp->pc1 = genjmp_0(s, OP_JMP); - lp->pc2 = new_label(s); - codegen(s, tree->cdr, NOVAL); - dispatch(s, lp->pc1); - codegen(s, tree->car, VAL); - pop(); - genjmp2(s, OP_JMPIF, cursp(), lp->pc2, NOVAL); - - loop_pop(s, val); - } - break; - case NODE_UNTIL: { + if (true_always(tree->car)) { + if (nt == NODE_UNTIL) { + if (val) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + goto exit; + } + } + else if (false_always(tree->car)) { + if (nt == NODE_WHILE) { + if (val) { + genop_1(s, OP_LOADNIL, cursp()); + push(); + } + goto exit; + } + } + + uint32_t pos = JMPLINK_START; struct loopinfo *lp = loop_push(s, LOOP_NORMAL); + if (!val) lp->reg = -1; lp->pc0 = new_label(s); - lp->pc1 = genjmp_0(s, OP_JMP); - lp->pc2 = new_label(s); - codegen(s, tree->cdr, NOVAL); - dispatch(s, lp->pc1); codegen(s, tree->car, VAL); pop(); - genjmp2(s, OP_JMPNOT, cursp(), lp->pc2, NOVAL); - + if (nt == NODE_WHILE) { + pos = genjmp2_0(s, OP_JMPNOT, cursp(), NOVAL); + } + else { + pos = genjmp2_0(s, OP_JMPIF, cursp(), NOVAL); + } + lp->pc1 = new_label(s); + codegen(s, tree->cdr, NOVAL); + genjmp(s, OP_JMP, lp->pc0); + dispatch(s, pos); loop_pop(s, val); } break; @@ -1948,15 +2431,12 @@ codegen(codegen_scope *s, node *tree, int val) { int n; - n = gen_values(s, tree, val, 0); - if (n >= 0) { - if (val) { + n = gen_values(s, tree, val, 0, 0); + if (val) { + if (n >= 0) { pop_n(n); genop_2(s, OP_ARRAY, cursp(), n); - push(); } - } - else if (val) { push(); } } @@ -1967,7 +2447,9 @@ codegen(codegen_scope *s, node *tree, int val) { int len = 0; mrb_bool update = FALSE; + int slimit = GEN_VAL_STACK_MAX; + if (cursp() >= GEN_LIT_ARY_MAX) slimit = INT16_MAX; while (tree) { if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) { if (len > 0) { @@ -1996,7 +2478,7 @@ codegen(codegen_scope *s, node *tree, int val) len++; } tree = tree->cdr; - if (val && cursp() > 127) { + if (val && cursp() >= slimit) { pop_n(len*2); if (!update) { genop_2(s, OP_HASH, cursp(), len); @@ -2156,7 +2638,7 @@ codegen(codegen_scope *s, node *tree, int val) idx = new_sym(s, nsym(n->cdr->car)); base = cursp()-1; if (n->cdr->cdr->car) { - nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1); + nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1, 14); if (nargs >= 0) { callargs = nargs; } @@ -2181,7 +2663,7 @@ codegen(codegen_scope *s, node *tree, int val) if (len == 2 && ((name[0] == '|' && name[1] == '|') || (name[0] == '&' && name[1] == '&'))) { - int pos; + uint32_t pos; pop(); if (val) { @@ -2201,7 +2683,7 @@ codegen(codegen_scope *s, node *tree, int val) if (nint(tree->car->car) == NODE_CALL) { if (callargs == CALL_MAXARGS) { pop(); - genop_1(s, OP_ARYPUSH, cursp()); + genop_2(s, OP_ARYPUSH, cursp(), 1); } else { pop_n(callargs); @@ -2258,7 +2740,7 @@ codegen(codegen_scope *s, node *tree, int val) } if (callargs == CALL_MAXARGS) { pop(); - genop_1(s, OP_ARYPUSH, cursp()); + genop_2(s, OP_ARYPUSH, cursp(), 1); } else { pop_n(callargs); @@ -2289,7 +2771,7 @@ codegen(codegen_scope *s, node *tree, int val) if (tree) { node *args = tree->car; if (args) { - n = gen_values(s, args, VAL, 0); + n = gen_values(s, args, VAL, 0, 14); if (n < 0) { n = noop = sendv = 1; push(); @@ -2370,7 +2852,7 @@ codegen(codegen_scope *s, node *tree, int val) if (ainfo < 0) codegen_error(s, "invalid yield (SyntaxError)"); push(); if (tree) { - n = gen_values(s, tree, VAL, 0); + n = gen_values(s, tree, VAL, 0, 14); if (n < 0) { n = sendv = 1; push(); @@ -2416,7 +2898,7 @@ codegen(codegen_scope *s, node *tree, int val) raise_error(s, "unexpected redo"); } else { - genjmp(s, OP_JMPUW, s->loop->pc2); + genjmp(s, OP_JMPUW, s->loop->pc1); } if (val) push(); break; @@ -2447,8 +2929,7 @@ codegen(codegen_scope *s, node *tree, int val) gen_move(s, cursp(), idx, val); } else { - int lv = search_upvar(s, nsym(tree), &idx); - genop_3(s, OP_GETUPVAR, cursp(), idx, lv); + gen_getupvar(s, cursp(), nsym(tree)); } push(); } @@ -2538,29 +3019,13 @@ codegen(codegen_scope *s, node *tree, int val) mrb_int i; mrb_bool overflow; - i = readint_mrb_int(s, p, base, FALSE, &overflow); + i = readint(s, p, base, FALSE, &overflow); if (overflow) { int off = new_litbn(s, p, base, FALSE); - genop_bs(s, OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); } 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 <= 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; - lit_int: - off = new_lit(s, mrb_int_value(s->mrb, i)); - genop_bs(s, OP_LOADL, cursp(), off); - } + gen_int(s, cursp(), i); } push(); } @@ -2573,7 +3038,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, f)); - genop_bs(s, OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); push(); } break; @@ -2590,7 +3055,7 @@ codegen(codegen_scope *s, node *tree, int val) mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, -f)); - genop_bs(s, OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); push(); } break; @@ -2603,26 +3068,13 @@ codegen(codegen_scope *s, node *tree, int val) mrb_int i; mrb_bool overflow; - i = readint_mrb_int(s, p, base, TRUE, &overflow); + i = readint(s, p, base, TRUE, &overflow); if (overflow) { int off = new_litbn(s, p, base, TRUE); - genop_bs(s, OP_LOADL, cursp(), off); + genop_2(s, OP_LOADL, cursp(), off); } else { - 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 { - int off = new_lit(s, mrb_int_value(s->mrb, i)); - genop_bs(s, OP_LOADL, cursp(), off); - } + gen_int(s, cursp(), i); } push(); } @@ -2630,10 +3082,13 @@ codegen(codegen_scope *s, node *tree, int val) default: if (val) { - int sym = new_sym(s, MRB_OPSYM_2(s->mrb, minus)); codegen(s, tree, VAL); pop(); - genop_3(s, OP_SEND, cursp(), sym, 0); + push_n(2);pop_n(2); /* space for receiver&block */ + mrb_sym minus = MRB_OPSYM_2(s->mrb, minus); + if (!gen_uniop(s, minus, cursp())) { + genop_3(s, OP_SEND, cursp(), new_sym(s, minus), 0); + } push(); } else { @@ -2652,7 +3107,7 @@ codegen(codegen_scope *s, node *tree, int val) int off = new_lit(s, mrb_str_new(s->mrb, p, len)); mrb_gc_arena_restore(s->mrb, ai); - genop_bs(s, OP_STRING, cursp(), off); + genop_2(s, OP_STRING, cursp(), off); push(); } break; @@ -2739,7 +3194,7 @@ codegen(codegen_scope *s, node *tree, int val) genop_1(s, OP_LOADSELF, cursp()); push(); - genop_bs(s, OP_STRING, cursp(), off); + genop_2(s, OP_STRING, cursp(), off); push(); push(); pop_n(3); sym = new_sym(s, MRB_OPSYM_2(s->mrb, tick)); /* ` */ @@ -2762,12 +3217,12 @@ codegen(codegen_scope *s, node *tree, int val) genop_1(s, OP_OCLASS, cursp()); genop_2(s, OP_GETMCNST, cursp(), sym); push(); - genop_bs(s, OP_STRING, cursp(), off); + genop_2(s, OP_STRING, cursp(), off); push(); if (p2 || p3) { if (p2) { /* opt */ off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop_bs(s, OP_STRING, cursp(), off); + genop_2(s, OP_STRING, cursp(), off); } else { genop_1(s, OP_LOADNIL, cursp()); @@ -2776,7 +3231,7 @@ codegen(codegen_scope *s, node *tree, int val) argc++; if (p3) { /* enc */ off = new_lit(s, mrb_str_new(s->mrb, p3, 1)); - genop_bs(s, OP_STRING, cursp(), off); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } @@ -2816,7 +3271,7 @@ codegen(codegen_scope *s, node *tree, int val) p = (char*)n->car; off = new_lit(s, mrb_str_new_cstr(s->mrb, p)); codegen(s, tree->car, VAL); - genop_bs(s, OP_STRING, cursp(), off); + genop_2(s, OP_STRING, cursp(), off); pop(); genop_1(s, OP_STRCAT, cursp()); push(); @@ -2824,14 +3279,14 @@ codegen(codegen_scope *s, node *tree, int val) if (n->cdr->car) { /* opt */ char *p2 = (char*)n->cdr->car; off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop_bs(s, OP_STRING, cursp(), off); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } if (n->cdr->cdr) { /* enc */ char *p2 = (char*)n->cdr->cdr; off = new_lit(s, mrb_str_new_cstr(s->mrb, p2)); - genop_bs(s, OP_STRING, cursp(), off); + genop_2(s, OP_STRING, cursp(), off); push(); argc++; } @@ -2858,7 +3313,7 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { int sym = new_sym(s, nsym(tree)); - genop_bs(s, OP_LOADSYM, cursp(), sym); + genop_2(s, OP_LOADSYM, cursp(), sym); push(); } break; @@ -2959,7 +3414,7 @@ codegen(codegen_scope *s, node *tree, int val) } else { idx = scope_body(s, body, val); - genop_bs(s, OP_EXEC, cursp(), idx); + genop_2(s, OP_EXEC, cursp(), idx); } if (val) { push(); @@ -2991,7 +3446,7 @@ codegen(codegen_scope *s, node *tree, int val) } else { idx = scope_body(s, tree->cdr->car, val); - genop_bs(s, OP_EXEC, cursp(), idx); + genop_2(s, OP_EXEC, cursp(), idx); } if (val) { push(); @@ -3012,7 +3467,7 @@ codegen(codegen_scope *s, node *tree, int val) } else { idx = scope_body(s, tree->cdr->car, val); - genop_bs(s, OP_EXEC, cursp(), idx); + genop_2(s, OP_EXEC, cursp(), idx); } if (val) { push(); @@ -3027,14 +3482,11 @@ codegen(codegen_scope *s, node *tree, int val) genop_1(s, OP_TCLASS, cursp()); push(); - genop_bs(s, OP_METHOD, cursp(), idx); + genop_2(s, OP_METHOD, cursp(), idx); push(); pop(); pop(); genop_2(s, OP_DEF, cursp(), sym); - if (val) { - genop_bs(s, OP_LOADSYM, cursp(), sym); - push(); - } + if (val) push(); } break; @@ -3048,13 +3500,10 @@ codegen(codegen_scope *s, node *tree, int val) pop(); genop_1(s, OP_SCLASS, cursp()); push(); - genop_bs(s, OP_METHOD, cursp(), idx); + genop_2(s, OP_METHOD, cursp(), idx); pop(); genop_2(s, OP_DEF, cursp(), sym); - if (val) { - genop_bs(s, OP_LOADSYM, cursp(), sym); - push(); - } + if (val) push(); } break; @@ -3214,9 +3663,9 @@ 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 = JMPLINK_START; + p->pc0 = p->pc1 = p->pc2 = JMPLINK_START; p->prev = s->loop; - p->acc = cursp(); + p->reg = cursp(); s->loop = p; return p; @@ -3232,11 +3681,16 @@ loop_break(codegen_scope *s, node *tree) else { struct loopinfo *loop; - if (tree) { - gen_retval(s, tree); - } loop = s->loop; + if (tree) { + if (loop->reg < 0) { + codegen(s, tree, NOVAL); + } + else { + gen_retval(s, tree); + } + } while (loop) { if (loop->type == LOOP_BEGIN) { loop = loop->prev; @@ -3256,11 +3710,16 @@ loop_break(codegen_scope *s, node *tree) if (loop->type == LOOP_NORMAL) { int tmp; - if (tree) { - gen_move(s, loop->acc, cursp(), 0); + if (loop->reg >= 0) { + if (tree) { + gen_move(s, loop->reg, cursp(), 0); + } + else { + genop_1(s, OP_LOADNIL, loop->reg); + } } - tmp = genjmp(s, OP_JMPUW, loop->pc3); - loop->pc3 = tmp; + tmp = genjmp(s, OP_JMPUW, loop->pc2); + loop->pc2 = tmp; } else { if (!tree) { @@ -3277,7 +3736,7 @@ loop_pop(codegen_scope *s, int val) if (val) { genop_1(s, OP_LOADNIL, cursp()); } - dispatch_linked(s, s->loop->pc3); + dispatch_linked(s, s->loop->pc2); s->loop = s->loop->prev; if (val) push(); } @@ -3308,16 +3767,18 @@ static struct RProc* generate_code(mrb_state *mrb, parser_state *p, int val) { codegen_scope *scope = scope_new(mrb, 0, 0); - struct RProc *proc; struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf jmpbuf; + struct RProc *proc; + + mrb->jmp = &jmpbuf; scope->mrb = mrb; scope->parser = p; scope->filename_sym = p->filename_sym; scope->filename_index = p->current_filename_index; - MRB_TRY(&scope->jmp) { - mrb->jmp = &scope->jmp; + MRB_TRY(mrb->jmp) { /* prepare irep */ codegen(scope, p->tree, val); proc = mrb_proc_new(mrb, scope->irep); @@ -3330,13 +3791,13 @@ generate_code(mrb_state *mrb, parser_state *p, int val) mrb->jmp = prev_jmp; return proc; } - MRB_CATCH(&scope->jmp) { + MRB_CATCH(mrb->jmp) { mrb_irep_decref(mrb, scope->irep); mrb_pool_close(scope->mpool); mrb->jmp = prev_jmp; return NULL; } - MRB_END_EXC(&scope->jmp); + MRB_END_EXC(mrb->jmp); } MRB_API struct RProc* @@ -3360,26 +3821,3 @@ mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep) mrb_irep_remove_lv(mrb, (mrb_irep*)irep->reps[i]); } } - -#undef OPCODE -#define Z 1 -#define S 3 -#define W 4 -/* instruction sizes */ -uint8_t mrb_insn_size[] = { -#define B 2 -#define BB 3 -#define BBB 4 -#define BS 4 -#define BSS 6 -#define SB 4 -#define OPCODE(_,x) x, -#include "mruby/ops.h" -#undef OPCODE -#undef B -#undef BB -#undef BS -#undef BSS -#undef SB -#undef BBB -}; |
