diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-11-26 10:34:31 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-11-26 10:34:31 +0900 |
| commit | 7150c6753933f12a2ba63769fb7b3a44cfcddd3d (patch) | |
| tree | cddfd89197039d98cac827837e58bd3041d88a2a | |
| parent | 6dedd6a940194881c3b66124ff277c4cb14d08bd (diff) | |
| download | mruby-7150c6753933f12a2ba63769fb7b3a44cfcddd3d.tar.gz mruby-7150c6753933f12a2ba63769fb7b3a44cfcddd3d.zip | |
Make `OP_JMP*` operand address to be relative.
Jump target address is `operand (16bit)` + `address of next instruction`.
In addition, `ilen` was made `uint32_t` so that `iseq` length limitation
of 65536 is removed. Only jump target address should be within signed
16bit (-32768 .. 32767).
| -rw-r--r-- | doc/mruby3.md | 5 | ||||
| -rw-r--r-- | include/mruby/irep.h | 3 | ||||
| -rw-r--r-- | include/mruby/ops.h | 8 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 84 | ||||
| -rw-r--r-- | src/codedump.c | 15 | ||||
| -rw-r--r-- | src/vm.c | 11 |
6 files changed, 83 insertions, 43 deletions
diff --git a/doc/mruby3.md b/doc/mruby3.md index bc0a74b00..3d9159940 100644 --- a/doc/mruby3.md +++ b/doc/mruby3.md @@ -137,6 +137,11 @@ No more operand extention * `OP_EXT2` * `OP_EXT3` +## Changed Instructions + +Jump addresses used to be specified by absolute offset from the start of `iseq`. Now they are relative offset from the address of the next instruction. + + ## `Random` now use `xoshiro128++`. For better and faster random number generation. diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 173f69037..04ab54ee2 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -73,7 +73,8 @@ typedef struct mrb_irep { /* debug info */ struct mrb_irep_debug_info* debug_info; - uint16_t ilen, plen, slen; + uint32_t ilen; + uint16_t plen, slen; uint8_t rlen; uint32_t refcnt; } mrb_irep; diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 02f227634..b006ae94f 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -49,10 +49,10 @@ OPCODE(GETMCNST, BB) /* R(a) = R(a)::Syms(b) */ OPCODE(SETMCNST, BB) /* R(a+1)::Syms(b) = R(a) */ OPCODE(GETUPVAR, BBB) /* R(a) = uvget(b,c) */ OPCODE(SETUPVAR, BBB) /* uvset(b,c,R(a)) */ -OPCODE(JMP, S) /* pc=a */ -OPCODE(JMPIF, BS) /* if R(a) pc=b */ -OPCODE(JMPNOT, BS) /* if !R(a) pc=b */ -OPCODE(JMPNIL, BS) /* if R(a)==nil pc=b */ +OPCODE(JMP, S) /* pc+=a */ +OPCODE(JMPIF, BS) /* if R(a) pc+=b */ +OPCODE(JMPNOT, BS) /* if !R(a) pc+=b */ +OPCODE(JMPNIL, BS) /* if R(a)==nil pc+=b */ OPCODE(JMPUW, S) /* unwind_and_jump_to(a) */ OPCODE(EXCEPT, B) /* R(a) = exc */ OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 2a7b9cf06..2e39e8930 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -39,7 +39,8 @@ enum looptype { struct loopinfo { enum looptype type; - int pc0, pc1, pc2, pc3, acc; + uint32_t pc0, pc1, pc2, pc3; + int acc; struct loopinfo *prev; }; @@ -53,9 +54,9 @@ 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; @@ -168,13 +169,15 @@ 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) { @@ -358,22 +361,39 @@ 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) +static void +gen_jmpdst(codegen_scope *s, uint32_t pc) { - uint16_t pos; + if (pc == 0) { + 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 jmp offset"); + } + gen_S(s, (uint16_t)off); + } +} + +static uint32_t +genjmp(codegen_scope *s, mrb_code i, uint32_t pc) +{ + 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) +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); @@ -393,7 +413,7 @@ genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val) gen_B(s, i); gen_B(s, (uint8_t)a); pos = s->pc; - gen_S(s, pc); + gen_jmpdst(s, pc); } return pos; } @@ -496,19 +516,26 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst) } } -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 = pos0 + 2; + int32_t offset; + int16_t newpos; + 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; for (;;) { @@ -1464,7 +1491,8 @@ 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; @@ -1739,7 +1767,7 @@ 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; @@ -1782,7 +1810,7 @@ codegen(codegen_scope *s, node *tree, int val) 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 (head) pop(); diff --git a/src/codedump.c b/src/codedump.c index 4f793b753..94d4f24c0 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -271,21 +271,26 @@ codedump(mrb_state *mrb, const mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_JMP, S); - printf("OP_JMP\t\t%03d\n", a); + i = pc - irep->iseq; + printf("OP_JMP\t\t%03d\n", (int)i+(int16_t)a); break; CASE(OP_JMPUW, S); - printf("OP_JMPUW\t\t%03d\n", a); + i = pc - irep->iseq; + printf("OP_JMPUW\t\t%03d\n", (int)i+(int16_t)a); break; CASE(OP_JMPIF, BS); - printf("OP_JMPIF\tR%d\t%03d\t", a, b); + i = pc - irep->iseq; + printf("OP_JMPIF\tR%d\t%03d\t", a, (int)i+(int16_t)b); print_lv_a(mrb, irep, a); break; CASE(OP_JMPNOT, BS); - printf("OP_JMPNOT\tR%d\t%03d\t", a, b); + i = pc - irep->iseq; + printf("OP_JMPNOT\tR%d\t%03d\t", a, (int)i+(int16_t)b); print_lv_a(mrb, irep, a); break; CASE(OP_JMPNIL, BS); - printf("OP_JMPNIL\tR%d\t%03d\t", a, b); + i = pc - irep->iseq; + printf("OP_JMPNIL\tR%d\t%03d\t", a, (int)i+(int16_t)b); print_lv_a(mrb, irep, a); break; CASE(OP_SENDV, BB); @@ -1274,26 +1274,26 @@ RETRY_TRY_BLOCK: } CASE(OP_JMP, S) { - pc = irep->iseq+a; + pc += (int16_t)a; JUMP; } CASE(OP_JMPIF, BS) { if (mrb_test(regs[a])) { - pc = irep->iseq+b; + pc += (int16_t)b; JUMP; } NEXT; } CASE(OP_JMPNOT, BS) { if (!mrb_test(regs[a])) { - pc = irep->iseq+b; + pc += (int16_t)b; JUMP; } NEXT; } CASE(OP_JMPNIL, BS) { if (mrb_nil_p(regs[a])) { - pc = irep->iseq+b; + pc += (int16_t)b; JUMP; } NEXT; @@ -1306,6 +1306,7 @@ RETRY_TRY_BLOCK: mrb_assert(mrb_integer_p(target)); a = (uint32_t)mrb_integer(target); mrb_assert(a >= 0 && a < irep->ilen); + a = a - (pc - irep->iseq); } CHECKPOINT_MAIN(RBREAK_TAG_JUMP) { ch = catch_handler_find(mrb, mrb->c->ci, pc, MRB_CATCH_FILTER_ENSURE); @@ -1319,7 +1320,7 @@ RETRY_TRY_BLOCK: CHECKPOINT_END(RBREAK_TAG_JUMP); mrb->exc = NULL; /* clear break object */ - pc = irep->iseq + a; + pc += (int16_t)a; JUMP; } |
