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).
This commit is contained in:
Yukihiro "Matz" Matsumoto
2020-11-26 10:34:31 +09:00
parent 6dedd6a940
commit 7150c67539
6 changed files with 83 additions and 43 deletions
+5
View File
@@ -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.
+2 -1
View File
@@ -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;
+4 -4
View File
@@ -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)) */
+56 -28
View File
@@ -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();
+10 -5
View File
@@ -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);
+6 -5
View File
@@ -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;
}