Allow more than 256 child `irep`; fix #5310

We have introduced following new instructions.

 * `OP_LAMBDA16`
 * `OP_BLOCK16`
 * `OP_METHOD16`
 * `OP_EXEC16`

Each instruction uses 16 bits operand for `reps` index. Since new
instructions are added, `mruby/c` VM should be updated.

Due to new instructions, dump format compatibility is lost, we have
increased `RITE_BINARY_MAJOR_VER`.

In addition, we have decreased the size of `refcnt` in `mrb_irep` from
`uint32_t` to `uint16_t`, which is reasonably big enough.
parent bd6b48fa
......@@ -51,7 +51,7 @@ MRB_API mrb_irep *mrb_read_irep_buf(mrb_state*, const void*, size_t);
/* Binary Format Version Major:Minor */
/* Major: Incompatible to prior versions */
/* Minor: Upper-compatible to prior versions */
#define RITE_BINARY_MAJOR_VER "01"
#define RITE_BINARY_MAJOR_VER "02"
#define RITE_BINARY_MINOR_VER "00"
#define RITE_BINARY_FORMAT_VER RITE_BINARY_MAJOR_VER RITE_BINARY_MINOR_VER
#define RITE_COMPILER_NAME "MATZ"
......
......@@ -75,8 +75,8 @@ typedef struct mrb_irep {
uint32_t ilen;
uint16_t plen, slen;
uint8_t rlen;
uint32_t refcnt;
uint16_t rlen;
uint16_t refcnt;
} mrb_irep;
#define MRB_ISEQ_NO_FREE 1
......
......@@ -100,14 +100,18 @@ OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b*2-1)) */
OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b*2)) */
OPCODE(HASHCAT, B) /* R(a) = hash_cat(R(a),R(a+1)) */
OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */
OPCODE(LAMBDA16, BS) /* R(a) = lambda(SEQ[b],L_LAMBDA) */
OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */
OPCODE(BLOCK16, BS) /* R(a) = lambda(SEQ[b],L_BLOCK) */
OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */
OPCODE(METHOD16, BS) /* R(a) = lambda(SEQ[b],L_METHOD) */
OPCODE(RANGE_INC, B) /* R(a) = range_new(R(a),R(a+1),FALSE) */
OPCODE(RANGE_EXC, B) /* R(a) = range_new(R(a),R(a+1),TRUE) */
OPCODE(OCLASS, B) /* R(a) = ::Object */
OPCODE(CLASS, BB) /* R(a) = newclass(R(a),Syms(b),R(a+1)) */
OPCODE(MODULE, BB) /* R(a) = newmodule(R(a),Syms(b)) */
OPCODE(EXEC, BB) /* R(a) = blockexec(R(a),SEQ[b]) */
OPCODE(EXEC16, BS) /* R(a) = blockexec(R(a),SEQ[b]) */
OPCODE(DEF, BB) /* R(a).newmethod(Syms(b),R(a+1)) */
OPCODE(ALIAS, BB) /* alias_method(target_class,Syms(a),Syms(b)) */
OPCODE(UNDEF, B) /* undef_method(target_class,Syms(a)) */
......
......@@ -464,6 +464,7 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV:
case OP_GETCONST: case OP_STRING: case OP_STRING16:
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;
genop_2(s, data.insn, dst, data.b);
......@@ -1630,7 +1631,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) {
int idx = lambda_body(s, tree, 1);
genop_2(s, OP_LAMBDA, cursp(), idx);
genop_bs(s, OP_LAMBDA, cursp(), idx);
push();
}
break;
......@@ -1639,7 +1640,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) {
int idx = lambda_body(s, tree, 1);
genop_2(s, OP_BLOCK, cursp(), idx);
genop_bs(s, OP_BLOCK, cursp(), idx);
push();
}
break;
......@@ -2910,7 +2911,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
else {
idx = scope_body(s, body, val);
genop_2(s, OP_EXEC, cursp(), idx);
genop_bs(s, OP_EXEC, cursp(), idx);
}
if (val) {
push();
......@@ -2942,7 +2943,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
else {
idx = scope_body(s, tree->cdr->car, val);
genop_2(s, OP_EXEC, cursp(), idx);
genop_bs(s, OP_EXEC, cursp(), idx);
}
if (val) {
push();
......@@ -2963,7 +2964,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
else {
idx = scope_body(s, tree->cdr->car, val);
genop_2(s, OP_EXEC, cursp(), idx);
genop_bs(s, OP_EXEC, cursp(), idx);
}
if (val) {
push();
......@@ -2978,7 +2979,7 @@ codegen(codegen_scope *s, node *tree, int val)
genop_1(s, OP_TCLASS, cursp());
push();
genop_2(s, OP_METHOD, cursp(), idx);
genop_bs(s, OP_METHOD, cursp(), idx);
push(); pop();
pop();
genop_2(s, OP_DEF, cursp(), sym);
......@@ -2999,7 +3000,7 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
genop_1(s, OP_SCLASS, cursp());
push();
genop_2(s, OP_METHOD, cursp(), idx);
genop_bs(s, OP_METHOD, cursp(), idx);
pop();
genop_2(s, OP_DEF, cursp(), sym);
if (val) {
......@@ -3032,7 +3033,7 @@ scope_add_irep(codegen_scope *s)
return;
}
else {
if (prev->irep->rlen == UINT8_MAX) {
if (prev->irep->rlen == UINT16_MAX) {
codegen_error(s, "too many nested blocks/methods");
}
s->irep = irep = mrb_add_irep(s->mrb);
......
......@@ -371,6 +371,15 @@ codedump(mrb_state *mrb, const mrb_irep *irep)
CASE(OP_METHOD, BB);
printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
CASE(OP_LAMBDA16, BS);
printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
CASE(OP_BLOCK16, BS);
printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
CASE(OP_METHOD16, BS);
printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, (void*)irep->reps[b]);
break;
CASE(OP_RANGE_INC, B);
printf("OP_RANGE_INC\tR%d\n", a);
break;
......
......@@ -2644,6 +2644,18 @@ RETRY_TRY_BLOCK:
c = OP_L_METHOD;
goto L_MAKE_LAMBDA;
}
CASE(OP_LAMBDA16, BS) {
c = OP_L_LAMBDA;
goto L_MAKE_LAMBDA;
}
CASE(OP_BLOCK16, BS) {
c = OP_L_BLOCK;
goto L_MAKE_LAMBDA;
}
CASE(OP_METHOD16, BS) {
c = OP_L_METHOD;
goto L_MAKE_LAMBDA;
}
CASE(OP_RANGE_INC, B) {
mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], FALSE);
......@@ -2699,7 +2711,11 @@ RETRY_TRY_BLOCK:
NEXT;
}
CASE(OP_EXEC, BB) {
CASE(OP_EXEC16, BS)
goto L_EXEC;
CASE(OP_EXEC, BB)
L_EXEC:
{
mrb_value recv = regs[a];
struct RProc *p;
const mrb_irep *nirep = irep->reps[b];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment