static void riPrintCode(const Proto* p) { const Instruction* code=p->code; int pc,n=p->sizecode; for (pc=0; pc<n; pc++) { Instruction i = code[pc]; OpCode o = GET_OPCODE(i); const char *name = luaP_opnames[o]; int line = luaG_getfuncline(p, pc); printf("(%4d) %4d - ", line, pc); switch (getOpMode(o)) { case iABC: printf("%-12s%4d %4d %4d%s", name, GETARG_A(i), GETARG_B(i), GETARG_C(i), GETARG_k(i) ? " (k)" : ""); break; case iABx: printf("%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); break; case iAsBx: printf("%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); break; case iAx: printf("%-12s%4d", name, GETARG_Ax(i)); break; case isJ: printf("%-12s%4d (%1d)", name, GETARG_sJ(i), !!GETARG_m(i)); break; } printf("\n"); } }
void Compiler::CompileLoadk(bool extraarg) { auto& ra = stack_.GetR(GETARG_A(cs_.instr_)); int karg = extraarg ? GETARG_Ax(cs_.proto_->code[cs_.curr_ + 1]) : GETARG_Bx(cs_.instr_); auto& k = stack_.GetK(karg); ra.Assign(k); }
const char* raviP_instruction_to_str(char *buf, size_t n, Instruction i) { OpCode o = GET_OPCODE(i); int a = GETARG_A(i); int b = GETARG_B(i); int c = GETARG_C(i); int ax = GETARG_Ax(i); int bx = GETARG_Bx(i); int sbx = GETARG_sBx(i); snprintf(buf, n, "%s ", luaP_opnames[o]); switch (getOpMode(o)) { case iABC: snprintf(buf+strlen(buf), n-strlen(buf), "A=%d", a); if (getBMode(o) != OpArgN) snprintf(buf + strlen(buf), n - strlen(buf), " B=%d", (getBMode(o) == OpArgK && ISK(b)) ? (MYK(INDEXK(b))) : b); if (getCMode(o) != OpArgN) snprintf(buf + strlen(buf), n - strlen(buf), " C=%d", (getCMode(o) == OpArgK && ISK(c)) ? (MYK(INDEXK(c))) : c); break; case iABx: snprintf(buf + strlen(buf), n - strlen(buf), "A=%d", a); if (getBMode(o) == OpArgK) snprintf(buf + strlen(buf), n - strlen(buf), " Bx=%d", MYK(bx)); if (getBMode(o) == OpArgU) snprintf(buf + strlen(buf), n - strlen(buf), " Bx=%d", bx); break; case iAsBx: snprintf(buf + strlen(buf), n - strlen(buf), "As=%d Bx=%d", a, sbx); break; case iAx: snprintf(buf + strlen(buf), n - strlen(buf), "Ax=%d", MYK(ax)); break; } return buf; }
const char *getobjname2 (LuaProto *p, int lastpc, int reg, std::string& name) { int pc; const char* name2 = p->getLocalName(reg + 1, lastpc); if(name2) { name = name2; } else { name.clear(); } if (!name.empty()) /* is a local? */ return "local"; /* else try symbolic execution */ pc = findsetreg(p, lastpc, reg); if (pc != -1) { /* could find instruction? */ Instruction i = p->instructions_[pc]; OpCode op = GET_OPCODE(i); switch (op) { case OP_MOVE: { int b = GETARG_B(i); /* move from 'b' to 'a' */ if (b < GETARG_A(i)) return getobjname2(p, pc, b, name); /* get name for 'b' */ break; } case OP_GETTABUP: case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ int t = GETARG_B(i); /* table index */ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ ? p->getLocalName(t + 1, pc) : p->getUpvalName(t); kname2(p, pc, k, name); return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; } case OP_GETUPVAL: { name = p->getUpvalName(GETARG_B(i)); return "upvalue"; } case OP_LOADK: case OP_LOADKX: { int b = (op == OP_LOADK) ? GETARG_Bx(i) : GETARG_Ax(p->instructions_[pc + 1]); if (p->constants[b].isString()) { name = p->constants[b].getString()->c_str(); return "constant"; } break; } case OP_SELF: { int k = GETARG_C(i); /* key index */ kname2(p, pc, k, name); return "method"; } default: break; /* go through to return NULL */ } } return NULL; /* could not find reasonable name */ }
static int do_getinstruction(lua_State *L) /** getinstruction(f,i) */ { const Proto* f=Pget(L,1); int pc=luaL_checkinteger(L,2); if (pc<=0 || pc>f->sizecode || f->code==NULL) return 0; pc--; { const Instruction* code=f->code; Instruction i=code[pc]; OpCode o=GET_OPCODE(i); int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); int ax=GETARG_Ax(i); int bx=GETARG_Bx(i); int sbx=GETARG_sBx(i); int line=getfuncline(f,pc); if (line>0) lua_pushinteger(L,line); else lua_pushnil(L); lua_pushstring(L,luaP_opnames[o]); switch (getOpMode(o)) { case iABC: lua_pushinteger(L,a); if (getBMode(o)!=OpArgN) lua_pushinteger(L,ISK(b) ? (MYK(INDEXK(b))) : b); else lua_pushnil(L); if (getCMode(o)!=OpArgN) lua_pushinteger(L,ISK(c) ? (MYK(INDEXK(c))) : c); else lua_pushnil(L); break; case iABx: lua_pushinteger(L,a); if (getBMode(o)==OpArgK) lua_pushinteger(L,MYK(bx)); else lua_pushinteger(L,bx); lua_pushnil(L); break; case iAsBx: lua_pushinteger(L,a); lua_pushinteger(L,sbx); lua_pushnil(L); break; case iAx: lua_pushinteger(L,MYK(ax)); lua_pushnil(L); lua_pushnil(L); break; } switch (o) { case OP_JMP: case OP_FORLOOP: case OP_FORPREP: case OP_TFORLOOP: lua_pop(L,1); lua_pushinteger(L,sbx+pc+2); break; default: break; } } return 5; }
/* local op, a, b, c, test = jit.util.bytecode(func, pc) */ static int ju_bytecode(lua_State *L) { Proto *pt = check_LCL(L)->l.p; int pc = luaL_checkint(L, 2); if (pc >= 1 && pc <= pt->sizecode) { Instruction ins = pt->code[pc-1]; OpCode op = GET_OPCODE(ins); if (pc > 1 && (((int)OP_SETLIST) << POS_OP) == (pt->code[pc-2] & (MASK1(SIZE_OP,POS_OP) | MASK1(SIZE_C,POS_C)))) { lua_pushstring(L, luaP_opnames[OP_SETLIST]); lua_pushnumber(L, (lua_Number)ins); /* Fake extended op. */ return 1; } if (op >= NUM_OPCODES) return 0; /* Just in case. */ lua_pushstring(L, luaP_opnames[op]); lua_pushinteger(L, GETARG_A(ins)); switch (getOpMode(op)) { case iABC: { int b = GETARG_B(ins), c = GETARG_C(ins); switch (getBMode(op)) { case OpArgN: lua_pushnil(L); break; case OpArgK: if (ISK(b)) b = -1-INDEXK(b); case OpArgR: case OpArgU: lua_pushinteger(L, b); break; } switch (getCMode(op)) { case OpArgN: lua_pushnil(L); break; case OpArgK: if (ISK(c)) c = -1-INDEXK(c); case OpArgR: case OpArgU: lua_pushinteger(L, c); break; } lua_pushboolean(L, testTMode(op)); return 5; } case iABx: { int bx = GETARG_Bx(ins); lua_pushinteger(L, getBMode(op) == OpArgK ? -1-bx : bx); return 3; } case iAsBx: lua_pushinteger(L, GETARG_sBx(ins)); return 3; } } return 0; }
static const char* getobjname(lua_State* L, CallInfo* ci, int stackpos, const char** name) { if (isLua(ci)) /* a Lua function? */ { Proto* p = ci_func(ci)->l.p; int pc = currentpc(L, ci); Instruction i; *name = luaF_getlocalname(p, stackpos + 1, pc); if (*name) /* is a local? */ return "local"; i = symbexec(p, pc, stackpos); /* try symbolic execution */ lua_assert(pc != -1); switch (GET_OPCODE(i)) { case OP_GETGLOBAL: { int g = GETARG_Bx(i); /* global index */ lua_assert(ttisstring(&p->k[g])); *name = svalue(&p->k[g]); return "global"; } case OP_MOVE: { int a = GETARG_A(i); int b = GETARG_B(i); /* move from `b' to `a' */ if (b < a) return getobjname(L, ci, b, name); /* get name for `b' */ break; } case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); return "field"; } case OP_GETUPVAL: { int u = GETARG_B(i); /* upvalue index */ *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; return "upvalue"; } case OP_SELF: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); return "method"; } default: break; } } return NULL; /* no useful name found */ }
static const char *getobjname (Proto *p, int lastpc, int reg, const char **name) { int pc; *name = luaF_getlocalname(p, reg + 1, lastpc); if (*name) /* is a local? */ return "local"; /* else try symbolic execution */ pc = findsetreg(p, lastpc, reg); if (pc != -1) { /* could find instruction? */ Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); switch (op) { case OP_MOVE: { int b = GETARG_B(i); /* move from 'b' to 'a' */ if (b < GETARG_A(i)) return getobjname(p, pc, b, name); /* get name for 'b' */ break; } case OP_GETTABUP: case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ int t = GETARG_B(i); /* table index */ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ ? luaF_getlocalname(p, t + 1, pc) : upvalname(p, t); kname(p, pc, k, name); return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; } case OP_GETUPVAL: { *name = upvalname(p, GETARG_B(i)); return "upvalue"; } case OP_LOADK: case OP_LOADKX: { int b = (op == OP_LOADK) ? GETARG_Bx(i) : GETARG_Ax(p->code[pc + 1]); if (ttisstring(&p->k[b])) { *name = svalue(&p->k[b]); return "constant"; } break; } case OP_SELF: { int k = GETARG_C(i); /* key index */ kname(p, pc, k, name); return "method"; } default: break; /* go through to return NULL */ } } return NULL; /* could not find reasonable name */ }
void Compiler::CompileClosure() { int a = GETARG_A(cs_.instr_); auto& ra = stack_.GetR(a); auto args = { cs_.values_.state, cs_.values_.closure, cs_.GetBase(), ra.GetTValue(), cs_.MakeInt(GETARG_Bx(cs_.instr_)) }; cs_.CreateCall("lll_closure", args); auto& ra1 = stack_.GetR(a + 1); CompileCheckcg(ra1.GetTValue()); }
void luaV_execute (lua_State *L) { CallInfo *ci = L->ci; LClosure *cl; TValue *k; StkId base; newframe: /* reentry point when frame changes (call/return) */ lua_assert(ci == L->ci); cl = clLvalue(ci->func); k = cl->p->k; base = ci->u.l.base; //printf( "s:%p\n", ci->u.l.savedpc ); /* main loop of interpreter */ for (;;) { Instruction i = *(ci->u.l.savedpc++); StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { Protect(traceexec(L)); } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == ci->u.l.base); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); // 命令出力 //printInst( ci->u.l.savedpc - 1 ); vmdispatch (GET_OPCODE(i)) { vmcase(OP_MOVE, setobjs2s(L, ra, RB(i)); ) vmcase(OP_LOADK, TValue *rb = k + GETARG_Bx(i); setobj2s(L, ra, rb); ) vmcase(OP_LOADKX, TValue *rb; lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); rb = k + GETARG_Ax(*ci->u.l.savedpc++); setobj2s(L, ra, rb); )
/* helper function to print out the opcode * as well as the arguments */ static void print_op(bInst op) { int args = opcode_args[GET_OPCODE(op)]; printf("\t%s", opcode_names[GET_OPCODE(op)]); if (args == ARG_NONE) return; if (HASARG_A(args)) printf(" %d", GETARG_A(op)); if (HASARG_B(args)) printf(" %d", GETARG_B(op)); if (HASARG_C(args)) printf(" %d", GETARG_C(op)); if (HASARG_Bx(args)) printf(" %d", GETARG_Bx(op)); if (HASARG_sBx(args)) printf(" %d", GETARG_sBx(op)); return; }
static void PrintCode(const Proto* f) { const Instruction* code=f->code; int pc,n=f->sizecode; for (pc=0; pc<n; pc++) { Instruction i=code[pc]; OpCode o=GET_OPCODE(i); int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); int bx=GETARG_Bx(i); int sbx=GETARG_sBx(i); int line=getline(f,pc); printf("\t%d\t",pc+1); if (line>0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); switch (getOpMode(o)) { case iABC: printf("%d",a); if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b); if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c); break; case iABx: if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); break; case iAsBx: if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); break; } switch (o) { case OP_LOADK: printf("\t; "); PrintConstant(f,bx); break; case OP_GETUPVAL: case OP_SETUPVAL: printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); break; case OP_GETGLOBAL: case OP_SETGLOBAL: printf("\t; %s",svalue(&f->k[bx])); break; case OP_GETTABLE: case OP_SELF: if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABLE: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_POW: case OP_EQ: case OP_LT: case OP_LE: if (ISK(b) || ISK(c)) { printf("\t; "); if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); printf(" "); if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); } break; case OP_JMP: case OP_FORLOOP: case OP_FORPREP: printf("\t; to %d",sbx+pc+2); break; case OP_CLOSURE: printf("\t; %p",VOID(f->p[bx])); break; case OP_SETLIST: if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c); break; default: break; } printf("\n"); } }
int luaU_guess_locals(Proto* f, int main) { intArray blocklist; LocVarArray locallist; int regassign[MAXARG_A+1]; int regusage[MAXARG_A+1]; int regblock[MAXARG_A+1]; int lastfree; int i,i2,x,pc; int func_endpc = FUNC_BLOCK_END(f); if (f->lineinfo != NULL) { return 0; } if (f->sizelocvars > 0) { return 0; } intArray_Init(&blocklist, MAXARG_A+1); addi(blocklist, func_endpc); LocVarArray_Init(&locallist, MAXARG_A+1); lastfree = 0; for (i=0; i<f->maxstacksize; i++) { regassign[i] = 0; regusage[i] = 0; regblock[i] = 0; } // parameters for (i = 0; i < f->numparams; i++) { add(locallist,0,func_endpc); regassign[lastfree] = 0; regusage[lastfree] = 1; regblock[lastfree] = func_endpc; lastfree++; } // vararg if (NEED_ARG(f)) { add(locallist,0,func_endpc); lastfree++; regassign[lastfree] = 0; regusage[lastfree] = 1; regblock[lastfree] = func_endpc; lastfree++; } #if LUA_VERSION_NUM == 501 // nil optimizations { Instruction i = f->code[0]; OpCode o = GET_OPCODE(i); int a = GETARG_A(i); int b = GETARG_B(i); int c = GETARG_C(i); int ixx,num_nil = -1; switch (o) { // read Ra only case OP_SETGLOBAL: case OP_SETUPVAL: case OP_TESTSET: num_nil = a; break; // read Rb only case OP_MOVE: case OP_UNM: case OP_NOT: case OP_LEN: if (!ISK(b)) { num_nil = b; } break; // read Rb and Rc case OP_GETTABLE: case OP_SETTABLE: case OP_SELF: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: case OP_EQ: case OP_LT: case OP_LE: if (!ISK(b)) { num_nil = b; } if (!ISK(c)) { num_nil = MAX(num_nil, c); } break; case OP_RETURN: // read Ra to a+b-2 // only return 1 value // move before return multiple values num_nil = MAX(num_nil, a+b-2); break; } for (ixx = lastfree; ixx <= num_nil; ixx++) { if (ixx!=num_nil) { add(locallist,0,last(blocklist)); lastfree++; } regassign[lastfree] = 0; regusage[lastfree] = 1; regblock[lastfree] = last(blocklist); lastfree++; } } #endif // start code checking for (pc = 0; pc < f->sizecode; pc++) { Instruction instr = f->code[pc]; OpCode o = GET_OPCODE(instr); int a = GETARG_A(instr); int b = GETARG_B(instr); int c = GETARG_C(instr); int bc = GETARG_Bx(instr); int sbc = GETARG_sBx(instr); int dest = 0; int setreg = -1; int setregto = -1; int setreg2 = -1; int loadreg = -1; int loadreg2 = -1; int loadreg3 = -1; int loadregto = -1; int intlocfrom = -1; int intlocto = -1; if ((o==OP_JMP) || (o==OP_FORPREP)) { dest = pc + sbc + 2; } else if ((pc+1!=f->sizecode) && (GET_OPCODE(f->code[pc+1])==OP_JMP)) { dest = pc + 1 + GETARG_sBx(f->code[pc+1]) + 2; } // check which registers were read or written to. switch (o) { case OP_MOVE: setreg = a; if (b<=a) { intlocfrom = b; intlocto = b; } loadreg = b; break; case OP_UNM: case OP_NOT: case OP_LEN: setreg = a; loadreg = b; break; case OP_LOADNIL: setreg = a; setregto = b; break; case OP_LOADK: #if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 case OP_LOADKX: #endif case OP_GETUPVAL: #if LUA_VERSION_NUM == 501 case OP_GETGLOBAL: #endif #if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 case OP_GETTABUP: #endif case OP_LOADBOOL: case OP_NEWTABLE: case OP_CLOSURE: setreg = a; break; case OP_GETTABLE: setreg = a; loadreg = b; if (!ISK(c)) { loadreg2 = c; } break; #if LUA_VERSION_NUM == 501 case OP_SETGLOBAL: #endif case OP_SETUPVAL: loadreg = a; break; #if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 case OP_SETTABUP: if (!ISK(b)) { loadreg2 = b; } if (!ISK(c)) { if (loadreg2==-1) { loadreg2 = c; } else { loadreg3 = c; } } break; #endif case OP_SETTABLE: loadreg = a; if (!ISK(b)) { loadreg2 = b; } if (!ISK(c)) { if (loadreg2==-1) { loadreg2 = c; } else { loadreg3 = c; } if ((a+1!=c) && (c>a)) { intlocto = c-1; } } intlocfrom = 0; if (a-1>=intlocto) { intlocto = a-1; } break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_POW: case OP_MOD: setreg = a; if (!ISK(b)) { loadreg = b; } if (!ISK(c)) { if (loadreg==-1) { loadreg = c; } else { loadreg2 = c; } } break; case OP_CONCAT: setreg = a; loadreg = b; loadregto = c; break; case OP_CALL: if (c==0) { setreg = a; setregto = f->maxstacksize; } else if (c>=2) { setreg = a; setregto = a+c-2; } else if (c==1) { intlocfrom = 0; intlocto = a-1; } if (b==0) { loadreg = a; loadregto = f->maxstacksize; } else { loadreg = a; loadregto = a+b-1; } break; case OP_RETURN: if (b==0) { loadreg = a; loadregto = f->maxstacksize; } else if (b>=2) { loadreg = a; loadregto = a+b-2; } break; case OP_TAILCALL: if (b==0) { loadreg = a; loadregto = f->maxstacksize; } else { loadreg = a; loadregto = a+b-1; } break; case OP_VARARG: if (b==0) { setreg = a; setregto = f->maxstacksize; } else { setreg = a; setregto = a+b-1; } break; case OP_SELF: setreg = a; setregto = a+1; loadreg = b; if (a>b) { intlocfrom = 0; intlocto = b; } if (!ISK(c)) { loadreg2 = c; } break; case OP_EQ: case OP_LT: case OP_LE: if (!ISK(b)) { loadreg = b; } if (!ISK(c)) { if (loadreg==-1) { loadreg = c; } else { loadreg2 = c; } } break; case OP_TEST: loadreg = a; break; case OP_TESTSET: setreg = a; loadreg = b; break; case OP_SETLIST: loadreg = a; if (b==0) { loadregto = f->maxstacksize; } else { loadregto = a+b; } break; case OP_FORLOOP: #if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 case OP_TFORCALL: #endif case OP_TFORLOOP: break; case OP_FORPREP: loadreg = a; loadregto = a+2; setreg = a; setregto = a+3; intlocfrom = a; intlocto = a+3; regassign[a] = pc; regassign[a+1] = pc; regassign[a+2] = pc; regassign[a+3] = pc+1; regblock[a] = dest; regblock[a+1] = dest; regblock[a+2] = dest; regblock[a+3] = dest-1; addi(blocklist, dest-1); if (GET_OPCODE(f->code[dest-2])==OP_JMP) { last(blocklist)--; } break; case OP_JMP: if (GET_OPCODE(f->code[dest-1]) == LUADEC_TFORLOOP) { int a = GETARG_A(f->code[dest-1]); int c = GETARG_C(f->code[dest-1]); setreg = a; setregto = a+c+2; loadreg = a; loadregto = a+2; intlocfrom = a; intlocto = a+c+2; regassign[a] = pc; regassign[a+1] = pc; regassign[a+2] = pc; regblock[a] = dest+1; regblock[a+1] = dest+1; regblock[a+2] = dest+1; for (x=a+3;x<=a+c+2;x++) { regassign[x] = pc+1; regblock[x] = dest-1; } } if (dest>pc) { addi(blocklist, dest-1); if (GET_OPCODE(f->code[dest-2])==OP_JMP) { last(blocklist)--; } } break; #if LUA_VERSION_NUM == 501 case OP_CLOSE: #endif #if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 case OP_EXTRAARG: #endif default: break; } for (i=1; i<blocklist.size; i++) { x = blocklist.values[i]; i2 = i-1; while ((i2>=0) && (blocklist.values[i2]<x)) { blocklist.values[i2+1] = blocklist.values[i2]; i2 = i2-1; } blocklist.values[i2+1] = x; } if (loadreg!=-1) { if (loadregto==-1) loadregto = loadreg; for (i=loadreg;i<=loadregto;i++) { regusage[i]--; } if (loadreg2!=-1) regusage[loadreg2]--; if (loadreg3!=-1) regusage[loadreg3]--; } if (setreg!=-1) { if (setregto==-1) setregto = setreg; for (i=setreg;i<=setregto;i++) { regusage[i]++; } if (setreg2!=-1) regusage[setreg2]++; } i2 = lastfree-1; for (i=lastfree; i<f->maxstacksize; i++) { if ((regusage[i]<0) || (regusage[i]>1)) { i2 = i; } if ((intlocfrom!=-1) && ((intlocfrom<=i) && (i<=intlocto))) { i2 = i; } } for (i=setreg; i<=setregto; i++) { if (i>i2) { regassign[i] = pc+1; regblock[i] = last(blocklist); } } for (i=lastfree; i<=i2; i++) { //fprintf(stderr,"%d %d %d %d\n",i,regassign[i],regblock[i],block); add(locallist,regassign[i],regblock[i]); lastfree++; } while (blocklist.size > 0 && last(blocklist) <= pc+1) { intArray_Pop(&blocklist); } if (blocklist.size == 0) { fprintf(stderr, "cannot find blockend > %d , pc = %d, f->sizecode = %d\n", pc+1, pc, f->sizecode); } while ((lastfree!=0) && (regblock[lastfree-1] <= pc+1)) { lastfree--; regusage[lastfree]=0; } } intArray_Clear(&blocklist); // print out information { int length = locallist.size; f->sizelocvars = length; if (f->sizelocvars>0) { f->locvars = luaM_newvector(glstate,f->sizelocvars,LocVar); for (i = 0; i < length; i++) { char names[10]; sprintf(names,"l_%d_%d",main,i); f->locvars[i].varname = luaS_new(glstate, names); f->locvars[i].startpc = locallist.values[i].startpc; f->locvars[i].endpc = locallist.values[i].endpc; } } } LocVarArray_Clear(&locallist); // run with all functions for (i=0; i<f->sizep; i++) { luaU_guess_locals(f->p[i],main+i+1); } return 1; }
static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { int pc; int last; /* stores position of last instruction that changed `reg' */ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ check(precheck(pt)); for (pc = 0; pc < lastpc; pc++) { const Instruction i = pt->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); int b = 0; int c = 0; checkreg(pt, a); switch (getOpMode(op)) { case iABC: { b = GETARG_B(i); c = GETARG_C(i); if (testOpMode(op, OpModeBreg)) { checkreg(pt, b); } else if (testOpMode(op, OpModeBrk)) check(checkRK(pt, b)); if (testOpMode(op, OpModeCrk)) check(checkRK(pt, c)); break; } case iABx: { b = GETARG_Bx(i); if (testOpMode(op, OpModeK)) check(b < pt->sizek); break; } case iAsBx: { b = GETARG_sBx(i); break; } } if (testOpMode(op, OpModesetA)) { if (a == reg) last = pc; /* change register `a' */ } if (testOpMode(op, OpModeT)) { check(pc+2 < pt->sizecode); /* check skip */ check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); } switch (op) { case OP_LOADBOOL: { check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ break; } case OP_LOADNIL: { if (a <= reg && reg <= b) last = pc; /* set registers from `a' to `b' */ break; } case OP_GETUPVAL: case OP_SETUPVAL: { check(b < pt->nups); break; } case OP_GETGLOBAL: case OP_SETGLOBAL: { check(ttisstring(&pt->k[b])); break; } case OP_SELF: { checkreg(pt, a+1); if (reg == a+1) last = pc; break; } case OP_CONCAT: { /* `c' is a register, and at least two operands */ check(c < MAXSTACK && b < c); break; } case OP_TFORLOOP: checkreg(pt, a+c+5); if (reg >= a) last = pc; /* affect all registers above base */ /* go through */ case OP_FORLOOP: checkreg(pt, a+2); /* go through */ case OP_JMP: { int dest = pc+1+b; check(0 <= dest && dest < pt->sizecode); /* not full check and jump is forward and do not skip `lastpc'? */ if (reg != NO_REG && pc < dest && dest <= lastpc) pc += b; /* do the jump */ break; } case OP_CALL: case OP_TAILCALL: { if (b != 0) { checkreg(pt, a+b-1); } c--; /* c = num. returns */ if (c == LUA_MULTRET) { check(checkopenop(pt, pc)); } else if (c != 0) checkreg(pt, a+c-1); if (reg >= a) last = pc; /* affect all registers above base */ break; } case OP_RETURN: { b--; /* b = num. returns */ if (b > 0) checkreg(pt, a+b-1); break; } case OP_SETLIST: { checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1); break; } case OP_CLOSURE: { int nup; check(b < pt->sizep); nup = pt->p[b]->nups; check(pc + nup < pt->sizecode); for (; nup>0; nup--) { OpCode op1 = GET_OPCODE(pt->code[pc+nup]); check(op1 == OP_GETUPVAL || op1 == OP_MOVE); } break; } default: break; } } return pt->code[last]; }
StkId luaV_execute (lua_State *L) { LClosure *cl; TObject *k; const Instruction *pc; callentry: /* entry point when calling new functions */ L->ci->u.l.pc = &pc; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); retentry: /* entry point when returning to old functions */ lua_assert(L->ci->state == CI_SAVEDPC || L->ci->state == (CI_SAVEDPC | CI_CALLING)); L->ci->state = CI_HASFRAME; /* activate frame */ pc = L->ci->u.l.savedpc; cl = &clvalue(L->base - 1)->l; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId base, ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L); if (L->ci->state & CI_YIELD) { /* did hook yield? */ L->ci->u.l.savedpc = pc - 1; L->ci->state = CI_YIELD | CI_SAVEDPC; return NULL; } } /* warning!! several calls may realloc the stack and invalidate `ra' */ base = L->base; ra = RA(i); lua_assert(L->ci->state & CI_HASFRAME); lua_assert(base == L->ci->base); lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(ra, RB(i)); break; } case OP_LOADK: { setobj2s(ra, KBx(i)); break; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ break; } case OP_LOADNIL: { TObject *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); break; } case OP_GETUPVAL: { int b = GETARG_B(i); setobj2s(ra, cl->upvals[b]->v); break; } case OP_GETGLOBAL: { TObject *rb = KBx(i); const TObject *v; lua_assert(ttisstring(rb) && ttistable(&cl->g)); v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0)); break; } case OP_GETTABLE: { StkId rb = RB(i); TObject *rc = RKC(i); if (ttistable(rb)) { const TObject *v = luaH_get(hvalue(rb), rc); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); } else setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); break; } case OP_SETGLOBAL: { lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); luaV_settable(L, &cl->g, KBx(i), ra); break; } case OP_SETUPVAL: { int b = GETARG_B(i); setobj(cl->upvals[b]->v, ra); /* write barrier */ break; } case OP_SETTABLE: { luaV_settable(L, ra, RKB(i), RKC(i)); break; } case OP_NEWTABLE: { int b = GETARG_B(i); b = fb2int(b); sethvalue(ra, luaH_new(L, b, GETARG_C(i))); luaC_checkGC(L); break; } case OP_SELF: { StkId rb = RB(i); TObject *rc = RKC(i); runtime_check(L, ttisstring(rc)); setobjs2s(ra+1, rb); if (ttistable(rb)) { const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); } else setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); break; } case OP_ADD: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) + nvalue(rc)); } else Arith(L, ra, rb, rc, TM_ADD); break; } case OP_SUB: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) - nvalue(rc)); } else Arith(L, ra, rb, rc, TM_SUB); break; } case OP_MUL: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) * nvalue(rc)); } else Arith(L, ra, rb, rc, TM_MUL); break; } case OP_DIV: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) / nvalue(rc)); } else Arith(L, ra, rb, rc, TM_DIV); break; } case OP_POW: { Arith(L, ra, RKB(i), RKC(i), TM_POW); break; } case OP_UNM: { const TObject *rb = RB(i); TObject temp; if (tonumber(rb, &temp)) { setnvalue(ra, -nvalue(rb)); } else { setnilvalue(&temp); if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) luaG_aritherror(L, RB(i), &temp); } break; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); break; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ base = L->base; setobjs2s(RA(i), base+b); luaC_checkGC(L); break; } case OP_JMP: { dojump(pc, GETARG_sBx(i)); break; } case OP_EQ: { if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_LT: { if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_LE: { if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_TEST: { TObject *rb = RB(i); if (l_isfalse(rb) == GETARG_C(i)) pc++; else { setobjs2s(ra, rb); dojump(pc, GETARG_sBx(*pc) + 1); } break; } case OP_CALL: case OP_TAILCALL: { StkId firstResult; int b = GETARG_B(i); int nresults; if (b != 0) L->top = ra+b; /* else previous instruction set top */ nresults = GETARG_C(i) - 1; firstResult = luaD_precall(L, ra); if (firstResult) { if (firstResult > L->top) { /* yield? */ lua_assert(L->ci->state == (CI_C | CI_YIELD)); (L->ci - 1)->u.l.savedpc = pc; (L->ci - 1)->state = CI_SAVEDPC; return NULL; } /* it was a C function (`precall' called it); adjust results */ luaD_poscall(L, nresults, firstResult); if (nresults >= 0) L->top = L->ci->top; } else { /* it is a Lua function */ if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); } else { /* tail call: put new frame in place of previous one */ int aux; base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ ra = RA(i); if (L->openupval) luaF_close(L, base); for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ setobjs2s(base+aux-1, ra+aux); (L->ci - 1)->top = L->top = base+aux; /* correct top */ lua_assert(L->ci->state & CI_SAVEDPC); (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ (L->ci - 1)->state = CI_SAVEDPC; L->ci--; /* remove new frame */ L->base = L->ci->base; } goto callentry; } break; } case OP_RETURN: { CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; lua_assert(L->ci->state & CI_HASFRAME); if (L->openupval) luaF_close(L, base); L->ci->state = CI_SAVEDPC; /* deactivate current function */ L->ci->u.l.savedpc = pc; /* previous function was running `here'? */ if (!(ci->state & CI_CALLING)) { lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); return ra; /* no: return */ } else { /* yes: continue its execution */ int nresults; lua_assert(ci->u.l.pc == &pc && ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra); if (nresults >= 0) L->top = L->ci->top; goto retentry; } } case OP_FORLOOP: { lua_Number step, idx, limit; const TObject *plimit = ra+1; const TObject *pstep = ra+2; if (!ttisnumber(ra)) luaG_runerror(L, "`for' initial value must be a number"); if (!tonumber(plimit, ra+1)) luaG_runerror(L, "`for' limit must be a number"); if (!tonumber(pstep, ra+2)) luaG_runerror(L, "`for' step must be a number"); step = nvalue(pstep); idx = nvalue(ra) + step; /* increment index */ limit = nvalue(plimit); if (step > 0 ? idx <= limit : idx >= limit) { dojump(pc, GETARG_sBx(i)); /* jump back */ chgnvalue(ra, idx); /* update index */ } break; } case OP_TFORLOOP: { int nvar = GETARG_C(i) + 1; StkId cb = ra + nvar + 2; /* call base */ setobjs2s(cb, ra); setobjs2s(cb+1, ra+1); setobjs2s(cb+2, ra+2); L->top = cb+3; /* func. + 2 args (state and index) */ luaD_call(L, cb, nvar); L->top = L->ci->top; ra = XRA(i) + 2; /* final position of first result */ cb = ra + nvar; do { /* move results to proper positions */ nvar--; setobjs2s(ra+nvar, cb+nvar); } while (nvar > 0); if (ttisnil(ra)) /* break loop? */ pc++; /* skip jump (break loop) */ else dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ break; } case OP_TFORPREP: { /* for compatibility only */ if (ttistable(ra)) { setobjs2s(ra+1, ra); setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); } dojump(pc, GETARG_sBx(i)); break; } case OP_SETLIST: case OP_SETLISTO: { int bc; int n; Table *h; runtime_check(L, ttistable(ra)); h = hvalue(ra); bc = GETARG_Bx(i); if (GET_OPCODE(i) == OP_SETLIST) n = (bc&(LFIELDS_PER_FLUSH-1)) + 1; else { n = L->top - ra - 1; L->top = L->ci->top; } bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ for (; n > 0; n--) setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */ break; } case OP_CLOSE: { luaF_close(L, ra); break; } case OP_CLOSURE: { Proto *p; Closure *ncl; int nup, j; p = cl->p->p[GETARG_Bx(i)]; nup = p->nups; ncl = luaF_newLclosure(L, nup, &cl->g); ncl->l.p = p; for (j=0; j<nup; j++, pc++) { if (GET_OPCODE(*pc) == OP_GETUPVAL) ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; else { lua_assert(GET_OPCODE(*pc) == OP_MOVE); ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } setclvalue(ra, ncl); luaC_checkGC(L); break; } } } }
static void patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest) { size_t i; mrb_code c; int argc = 0; for (i = 0; i < irep->ilen; i++) { c = irep->iseq[i]; switch(GET_OPCODE(c)){ case OP_ENTER: { mrb_aspec ax = GETARG_Ax(c); /* extra 1 means a slot for block */ argc = MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1; } break; case OP_EPUSH: patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1); break; case OP_LAMBDA: { int arg_c = GETARG_c(c); if (arg_c & OP_L_CAPTURE) { patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1); } } break; case OP_SEND: if (GETARG_C(c) != 0) { break; } { mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; } } break; case OP_MOVE: /* src part */ if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) { mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; } } /* dst part */ if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) { mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg; } } break; } } }
/* * This function is used to update the local variable type hints. * */ void vm_op_hint_locals(char *locals, int stacksize, TValue *k, const Instruction i) { int ra,rb,rc; char ra_type = LUA_TNONE; #define reset_local() memset(locals, LUA_TNONE, stacksize * sizeof(char)) #define RK_TYPE(rk) (ISK(rk) ? ttype(k+INDEXK(rk)) : locals[rk]) // make sure ra is a valid local register. switch (GET_OPCODE(i)) { case OP_MOVE: rb = GETARG_B(i); ra_type = locals[rb]; break; case OP_LOADK: rb = GETARG_Bx(i); ra_type = ttype(k + rb); break; case OP_LOADBOOL: if (GETARG_C(i)) { reset_local(); // jmp, reset types. } else { ra_type = LUA_TBOOLEAN; } break; case OP_LOADNIL: ra = GETARG_A(i); rb = GETARG_B(i); do { locals[rb--] = LUA_TNIL; } while (rb >= ra); return; case OP_GETUPVAL: case OP_GETGLOBAL: case OP_GETTABLE: // reset 'ra' type don't know type at compile-time. break; case OP_SETUPVAL: case OP_SETGLOBAL: case OP_SETTABLE: // no changes to locals. return; case OP_NEWTABLE: ra_type = LUA_TTABLE; break; case OP_SELF: // 'ra + 1' will be a table. ra = GETARG_A(i); locals[ra + 1] = LUA_TTABLE; // reset 'ra' type don't know type at compile-time. break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: // if 'b' & 'c' are numbers, then 'ra' will be a number rb = GETARG_B(i); rc = GETARG_C(i); if(RK_TYPE(rb) == LUA_TNUMBER && RK_TYPE(rc) == LUA_TNUMBER) { ra_type = LUA_TNUMBER; } break; case OP_UNM: // if 'b' is a number, then 'ra' will be a number rb = GETARG_B(i); if(RK_TYPE(rb) == LUA_TNUMBER) { ra_type = LUA_TNUMBER; } break; case OP_NOT: ra_type = LUA_TBOOLEAN; break; case OP_LEN: rb = GETARG_B(i); switch (locals[rb]) { case LUA_TTABLE: case LUA_TSTRING: ra_type = LUA_TNUMBER; break; default: // 'ra' type unknown. break; } break; case OP_CONCAT: rb = GETARG_B(i); rc = GETARG_C(i); // if all values 'rb' -> 'rc' are strings/numbers then 'ra' will be a string. ra_type = LUA_TSTRING; while(rb <= rc) { if(locals[rb] != LUA_TNUMBER && locals[rb] != LUA_TSTRING) { // we don't know what type 'ra' will be. ra_type = LUA_TNONE; break; } rb++; } break; case OP_JMP: case OP_EQ: case OP_LT: case OP_LE: case OP_TEST: case OP_TESTSET: reset_local(); // jmp, reset types. break; case OP_CALL: ra = GETARG_A(i); // just reset 'ra' -> top of the stack. while(ra < stacksize) { locals[ra++] = LUA_TNONE; } return; case OP_TAILCALL: case OP_RETURN: case OP_FORLOOP: case OP_FORPREP: case OP_TFORLOOP: reset_local(); return; case OP_SETLIST: case OP_CLOSE: return; case OP_CLOSURE: ra_type = LUA_TFUNCTION; break; case OP_VARARG: ra = GETARG_A(i); rb = ra + GETARG_B(i) - 1; // reset type for 'ra' -> 'ra + rb - 1' while(ra <= rb) { locals[ra++] = LUA_TNONE; } return; default: return; } ra = GETARG_A(i); }
void BijouBlock_dump2(VM, BijouBlock* b, int level) { char * str; size_t x; INDENT; printf("; block at: %p, %s (level %d)\n", (void *)b, b->funcname != NULL ? b->funcname : "", level); INDENT; printf("; %zu registers\n", b->regc); INDENT; printf("; constants (%zu)\n", kv_size(b->k)); for (x = 0; x < kv_size(b->k); ++x) { str = TValue_to_string(kv_A(b->k, x)); int s = ttisstring(&kv_A(b->k, x)); INDENT; printf("\t%zu: (%s) %s%s%s\n", x, TValue_type_to_string(kv_A(b->k, x)), s ? "\"" : "", str, s ? "\"" : ""); if (ttisnumber(&kv_A(b->k, x))) B_FREE(str); } INDENT; printf("; locals (%zu)\n", kv_size(b->locals)); for (x = 0; x < kv_size(b->locals); ++x) { str = TValue_to_string(kv_A(b->locals, x)); INDENT; printf("\t%zu: (%s) %s\n", x, TValue_type_to_string(kv_A(b->locals, x)), str); if (ttisnumber(&kv_A(b->locals, x))) B_FREE(str); } INDENT; printf("; upvals (%zu)\n", kv_size(b->upvals)); for (x = 0; x < kv_size(b->upvals); ++x) { str = TValue_to_string(kv_A(b->upvals, x)); INDENT; printf("\t%zu: (%s) %s\n", x, TValue_type_to_string(kv_A(b->upvals, x)), str); if (ttisnumber(&kv_A(b->upvals, x))) B_FREE(str); } INDENT; printf("; code section (%zu instructions)\n", kv_size(b->code)); for (x = 0; x < kv_size(b->code); ++x) { bInst i = kv_A(b->code, x); INDENT; print_op(i); printf("\t"); switch (GET_OPCODE(i)) { case OP_MOVE: printf("; R[%d] = R[%d]", GETARG_A(i), GETARG_B(i)); break; case OP_LOADK: printf("; R[%d] = K[%d]", GETARG_A(i), GETARG_Bx(i)); break; case OP_LOADBOOL: printf("; R[%d] = %s", GETARG_A(i), GETARG_B(i) == 0 ? "false" : "true" ); break; case OP_LOADNULL: printf("; R[%d] = null", GETARG_A(i)); break; case OP_GETGLOBAL: printf("; R[%d] = globals[K[%d]]", GETARG_A(i), GETARG_Bx(i)); break; case OP_SETGLOBAL: printf("; globals[K[%d]] = R[%d]", GETARG_Bx(i), GETARG_A(i)); break; case OP_GETLOCAL: printf("; R[%d] = locals[K[%d]]", GETARG_A(i), GETARG_Bx(i)); break; case OP_SETLOCAL: printf("; locals[K[%d]] = R[%d]", GETARG_Bx(i), GETARG_A(i)); break; case OP_ADD: printf("; R[%d] = RK[%d] + RK[%d]", GETARG_A(i), GETARG_B(i), GETARG_C(i)); break; case OP_SUB: printf("; R[%d] = RK[%d] - RK[%d]", GETARG_A(i), GETARG_B(i), GETARG_C(i)); break; case OP_MUL: printf("; R[%d] = RK[%d] * RK[%d]", GETARG_A(i), GETARG_B(i), GETARG_C(i)); break; case OP_DIV: printf("; R[%d] = RK[%d] / RK[%d]", GETARG_A(i), GETARG_B(i), GETARG_C(i)); break; case OP_POW: printf("; R[%d] = RK[%d] ** RK[%d]", GETARG_A(i), GETARG_B(i), GETARG_C(i)); break; case OP_REM: printf("; R[%d] = RK[%d] %% RK[%d]", GETARG_A(i), GETARG_B(i), GETARG_C(i)); break; case OP_UNM: printf("; R[%d] = -RK[%d]", GETARG_A(i), GETARG_B(i)); break; case OP_NOT: printf("; R[%d] = !RK[%d]", GETARG_A(i), GETARG_B(i)); break; case OP_CLOSURE: printf("; R[%d] = ", GETARG_A(i)); if (ISK(GETARG_Bx(i))) { BijouFunction *func = kv_A(vm->functions, GETARG_Bx(i) & ~0x100); printf("%s\n", func->name); } else printf("closure[%d] (%s)\n", GETARG_Bx(i), b->children[GETARG_Bx(i)]->funcname); break; case OP_CALL: printf("; R[%d] = R[%d](", GETARG_A(i), GETARG_B(i)); size_t x; for (x = 0; x < GETARG_C(i); ++x) { printf("R[%zu], ", x); } if (x > 0) { printf("\b\b"); } printf(")"); break; case OP_GETEXTERNAL: printf("; R[%d] = closure(K[%d])", GETARG_A(i), GETARG_B(i)); break; } printf("\n"); } INDENT; printf("; functions (%zu definitions)\n", b->numchildren); for (x = 0; x < b->numchildren; ++x) { BijouBlock_dump2(vm, b->children[x], level + 1); } }
static void PrintCode(const Proto* f) { const Instruction* code=f->code; int pc,n=f->sizecode; for (pc=0; pc<n; pc++) { Instruction i=code[pc]; OpCode o=GET_OPCODE(i); int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); int ax=GETARG_Ax(i); int bx=GETARG_Bx(i); int sb=GETARG_sB(i); int sc=GETARG_sC(i); int sbx=GETARG_sBx(i); int isk=GETARG_k(i); int line=getfuncline(f,pc); printf("\t%d\t",pc+1); if (line>0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); switch (o) { case OP_MOVE: printf("%d %d",a,b); break; case OP_LOADI: printf("%d %d",a,sbx); break; case OP_LOADF: printf("%d %d",a,sbx); break; case OP_LOADK: printf("%d %d",a,bx); printf("\t; "); PrintConstant(f,bx); break; case OP_LOADKX: printf("%d",a); break; case OP_LOADBOOL: printf("%d %d %d",a,b,c); if (c) printf("\t; to %d",pc+2); break; case OP_LOADNIL: printf("%d %d",a,b); printf("\t; %d out",b+1); break; case OP_GETUPVAL: printf("%d %d",a,b); printf("\t; %s",UPVALNAME(b)); break; case OP_SETUPVAL: printf("%d %d",a,b); printf("\t; %s",UPVALNAME(b)); break; case OP_GETTABUP: printf("%d %d %d",a,b,c); printf("\t; %s",UPVALNAME(b)); printf(" "); PrintConstant(f,c); break; case OP_GETTABLE: printf("%d %d %d",a,b,c); break; case OP_GETI: printf("%d %d %d",a,b,c); break; case OP_GETFIELD: printf("%d %d %d",a,b,c); printf("\t; "); PrintConstant(f,c); break; case OP_SETTABUP: printf("%d %d %d%s",a,b,c, isk ? "k" : ""); printf("\t; %s",UPVALNAME(a)); printf(" "); PrintConstant(f,b); if (isk) { printf(" "); PrintConstant(f,c); } break; case OP_SETTABLE: printf("%d %d %d%s",a,b,c, isk ? "k" : ""); if (isk) { printf("\t; "); PrintConstant(f,c); } break; case OP_SETI: printf("%d %d %d%s",a,b,c, isk ? "k" : ""); if (isk) { printf("\t; "); PrintConstant(f,c); } break; case OP_SETFIELD: printf("%d %d %d%s",a,b,c, isk ? "k" : ""); printf("\t; "); PrintConstant(f,b); if (isk) { printf(" "); PrintConstant(f,c); } break; case OP_NEWTABLE: printf("%d %d %d",a,b,c); break; case OP_SELF: printf("%d %d %d%s",a,b,c, isk ? "k" : ""); if (isk) { printf("\t; "); PrintConstant(f,c); } break; case OP_ADDI: printf("%d %d %d",a,b,sc); break; case OP_SUBI: printf("%d %d %d",a,b,sc); break; case OP_MULI: printf("%d %d %d",a,b,sc); break; case OP_MODI: printf("%d %d %d",a,b,sc); break; case OP_POWI: printf("%d %d %d",a,b,sc); break; case OP_DIVI: printf("%d %d %d",a,b,sc); break; case OP_IDIVI: printf("%d %d %d",a,b,sc); break; case OP_BANDK: printf("%d %d %d",a,b,c); printf("\t; "); PrintConstant(f,c); break; case OP_BORK: printf("%d %d %d",a,b,c); printf("\t; "); PrintConstant(f,c); break; case OP_BXORK: printf("%d %d %d",a,b,c); printf("\t; "); PrintConstant(f,c); break; case OP_SHRI: printf("%d %d %d",a,b,c); break; case OP_SHLI: printf("%d %d %d",a,b,c); break; case OP_ADD: printf("%d %d %d",a,b,c); break; case OP_SUB: printf("%d %d %d",a,b,c); break; case OP_MUL: printf("%d %d %d",a,b,c); break; case OP_MOD: printf("%d %d %d",a,b,c); break; case OP_POW: printf("%d %d %d",a,b,c); break; case OP_DIV: printf("%d %d %d",a,b,c); break; case OP_IDIV: printf("%d %d %d",a,b,c); break; case OP_BAND: printf("%d %d %d",a,b,c); break; case OP_BOR: printf("%d %d %d",a,b,c); break; case OP_BXOR: printf("%d %d %d",a,b,c); break; case OP_SHL: printf("%d %d %d",a,b,c); break; case OP_SHR: printf("%d %d %d",a,b,c); break; case OP_UNM: printf("%d %d",a,b); break; case OP_BNOT: printf("%d %d",a,b); break; case OP_NOT: printf("%d %d",a,b); break; case OP_LEN: printf("%d %d",a,b); break; case OP_CONCAT: printf("%d %d",a,b); break; case OP_CLOSE: printf("%d",a); break; case OP_JMP: printf("%d",GETARG_sJ(i)); printf("\t; to %d",GETARG_sJ(i)+pc+2); break; case OP_EQ: printf("%d %d %d",a,b,isk); break; case OP_LT: printf("%d %d %d",a,b,isk); break; case OP_LE: printf("%d %d %d",a,b,isk); break; case OP_EQK: printf("%d %d %d",a,b,isk); printf("\t; "); PrintConstant(f,b); break; case OP_EQI: printf("%d %d %d",a,sb,isk); break; case OP_LTI: printf("%d %d %d",a,sb,isk); break; case OP_LEI: printf("%d %d %d",a,sb,isk); break; case OP_GTI: printf("%d %d %d",a,sb,isk); break; case OP_GEI: printf("%d %d %d",a,sb,isk); break; case OP_TEST: printf("%d %d",a,isk); break; case OP_TESTSET: printf("%d %d %d",a,b,isk); break; case OP_CALL: printf("%d %d %d",a,b,c); printf("\t; "); if (b==0) printf("all in "); else printf("%d in ",b-1); if (c==0) printf("all out"); else printf("%d out",c-1); break; case OP_TAILCALL: printf("%d %d %d",a,b,c); printf("\t; %d in",b-1); break; case OP_RETURN: printf("%d %d %d",a,b,c); printf("\t; "); if (b==0) printf("all out"); else printf("%d out",b-1); break; case OP_RETURN0: break; case OP_RETURN1: printf("%d",a); break; case OP_FORLOOP1: printf("%d %d",a,bx); printf("\t; to %d",pc-bx+2); break; case OP_FORPREP1: printf("%d %d",a,bx); printf("\t; to %d",pc+bx+2); break; case OP_FORLOOP: printf("%d %d",a,bx); printf("\t; to %d",pc-bx+2); break; case OP_FORPREP: printf("%d %d",a,bx); printf("\t; to %d",pc+bx+2); break; case OP_TFORCALL: printf("%d %d",a,c); break; case OP_TFORLOOP: printf("%d %d",a,bx); printf("\t; to %d",pc-bx+2); break; case OP_SETLIST: printf("%d %d %d",a,b,c); break; case OP_CLOSURE: printf("%d %d",a,bx); printf("\t; %p",VOID(f->p[bx])); break; case OP_VARARG: printf("%d %d",a,c); printf("\t; "); if (c==0) printf("all out"); else printf("%d out",c-1); break; case OP_PREPVARARG: printf("%d",a); break; case OP_EXTRAARG: printf("%d",ax); printf("\t; "); PrintConstant(f,ax); break; } printf("\n"); } }
static Instruction symbexec (const Proto *pt, int lastpc, int reg) { int pc; int last; /* stores position of last instruction that changed `reg' */ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ check(precheck(pt)); for (pc = 0; pc < lastpc; pc++) { Instruction i = pt->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); int b = 0; int c = 0; check(op < NUM_OPCODES); checkreg(pt, a); switch (getOpMode(op)) { case iABC: { b = GETARG_B(i); c = GETARG_C(i); check(checkArgMode(pt, b, getBMode(op))); check(checkArgMode(pt, c, getCMode(op))); break; } case iABx: { b = GETARG_Bx(i); if (getBMode(op) == OpArgK) check(b < pt->sizek); break; } case iAsBx: { b = GETARG_sBx(i); if (getBMode(op) == OpArgR) { int dest = pc+1+b; check(0 <= dest && dest < pt->sizecode); if (dest > 0) { /* cannot jump to a setlist count */ Instruction d = pt->code[dest-1]; check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)); } } break; } } if (testAMode(op)) { if (a == reg) last = pc; /* change register `a' */ } if (testTMode(op)) { check(pc+2 < pt->sizecode); /* check skip */ check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); } switch (op) { case OP_LOADBOOL: { check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ break; } case OP_LOADNIL: { if (a <= reg && reg <= b) last = pc; /* set registers from `a' to `b' */ break; } case OP_GETUPVAL: case OP_SETUPVAL: { check(b < pt->nups); break; } case OP_GETGLOBAL: case OP_SETGLOBAL: { check(ttisstring(&pt->k[b])); break; } case OP_SELF: { checkreg(pt, a+1); if (reg == a+1) last = pc; break; } case OP_CONCAT: { check(b < c); /* at least two operands */ break; } case OP_TFORLOOP: { check(c >= 1); /* at least one result (control variable) */ checkreg(pt, a+2+c); /* space for results */ if (reg >= a+2) last = pc; /* affect all regs above its base */ break; } case OP_FORLOOP: case OP_FORPREP: checkreg(pt, a+3); /* go through */ case OP_JMP: { int dest = pc+1+b; /* not full check and jump is forward and do not skip `lastpc'? */ if (reg != NO_REG && pc < dest && dest <= lastpc) pc += b; /* do the jump */ break; } case OP_CALL: case OP_TAILCALL: { if (b != 0) { checkreg(pt, a+b-1); } c--; /* c = num. returns */ if (c == LUA_MULTRET) { check(checkopenop(pt, pc)); } else if (c != 0) checkreg(pt, a+c-1); if (reg >= a) last = pc; /* affect all registers above base */ break; } case OP_RETURN: { b--; /* b = num. returns */ if (b > 0) checkreg(pt, a+b-1); break; } case OP_SETLIST: { if (b > 0) checkreg(pt, a + b); if (c == 0) pc++; break; } case OP_CLOSURE: { int nup; check(b < pt->sizep); nup = pt->p[b]->nups; check(pc + nup < pt->sizecode); for (; nup>0; nup--) { OpCode op1 = GET_OPCODE(pt->code[pc+nup]); check(op1 == OP_GETUPVAL || op1 == OP_MOVE); } break; } case OP_VARARG: { check((pt->is_vararg & VARARG_ISVARARG) && !(pt->is_vararg & VARARG_NEEDSARG)); b--; if (b == LUA_MULTRET) check(checkopenop(pt, pc)); checkreg(pt, a+b-1); break; } default: break; } } return pt->code[last]; }
mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { /* assert(mrb_proc_cfunc_p(proc)) */ mrb_irep *irep = proc->body.irep; mrb_code *pc = irep->iseq; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; mrb_value *regs; mrb_code i; int ai = mrb->arena_idx; jmp_buf c_jmp; jmp_buf *prev_jmp; #ifdef DIRECT_THREADED static void *optable[] = { &&L_OP_NOP, &&L_OP_MOVE, &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL, &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF, &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL, &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV, &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST, &&L_OP_GETUPVAR, &&L_OP_SETUPVAR, &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT, &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP, &&L_OP_SEND, &&L_OP_FSEND, &&L_OP_VSEND, &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER, &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH, &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST, &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH, &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS, &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC, &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS, &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR, }; #endif if (setjmp(c_jmp) == 0) { prev_jmp = mrb->jmp; mrb->jmp = &c_jmp; } else { goto L_RAISE; } if (!mrb->stack) { stack_init(mrb); } mrb->ci->proc = proc; mrb->ci->nregs = irep->nregs + 2; regs = mrb->stack; INIT_DISPACTH { CASE(OP_NOP) { /* do nothing */ NEXT; } CASE(OP_MOVE) { /* A B R(A) := R(B) */ #if 0 regs[GETARG_A(i)] = regs[GETARG_B(i)]; #elif 1 int a = GETARG_A(i); int b = GETARG_B(i); regs[a].tt = regs[b].tt; regs[a].value = regs[b].value; #else memcpy(regs+GETARG_A(i), regs+GETARG_B(i), sizeof(mrb_value)); #endif NEXT; } CASE(OP_LOADL) { /* A Bx R(A) := Pool(Bx) */ regs[GETARG_A(i)] = pool[GETARG_Bx(i)]; NEXT; } CASE(OP_LOADI) { /* A Bx R(A) := sBx */ SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i)); NEXT; } CASE(OP_LOADSYM) { /* A B R(A) := Sym(B) */ SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]); NEXT; } CASE(OP_LOADNIL) { /* A B R(A) := nil */ int a = GETARG_A(i); SET_NIL_VALUE(regs[a]); NEXT; } CASE(OP_LOADSELF) { /* A R(A) := self */ regs[GETARG_A(i)] = mrb->stack[0]; NEXT; } CASE(OP_LOADT) { /* A R(A) := true */ regs[GETARG_A(i)] = mrb_true_value(); NEXT; } CASE(OP_LOADF) { /* A R(A) := false */ regs[GETARG_A(i)] = mrb_false_value(); NEXT; } CASE(OP_GETGLOBAL) { /* A B R(A) := getglobal(Sym(B)) */ regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETGLOBAL) { /* setglobal(Sym(b), R(A)) */ mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETSPECIAL) { /* A Bx R(A) := Special[Bx] */ regs[GETARG_A(i)] = mrb_vm_special_get(mrb, GETARG_Bx(i)); NEXT; } CASE(OP_SETSPECIAL) { /* A Bx Special[Bx] := R(A) */ mrb_vm_special_set(mrb, GETARG_Bx(i), regs[GETARG_A(i)]); NEXT; } CASE(OP_GETIV) { /* A Bx R(A) := ivget(Bx) */ regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETIV) { /* ivset(Sym(B),R(A)) */ mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETCV) { /* A B R(A) := ivget(Sym(B)) */ regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETCV) { /* ivset(Sym(B),R(A)) */ mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETCONST) { /* A B R(A) := constget(Sym(B)) */ regs[GETARG_A(i)] = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETCONST) { /* A B constset(Sym(B),R(A)) */ mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETMCNST) { /* A B C R(A) := R(C)::Sym(B) */ int a = GETARG_A(i); regs[a] = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETMCNST) { /* A B C R(A+1)::Sym(B) := R(A) */ int a = GETARG_A(i); mrb_const_set(mrb, regs[a+1], syms[GETARG_Bx(i)], regs[a]); NEXT; } CASE(OP_GETUPVAR) { /* A B C R(A) := uvget(B,C) */ regs[GETARG_A(i)] = uvget(mrb, GETARG_C(i), GETARG_B(i)); NEXT; } CASE(OP_SETUPVAR) { /* A B C uvset(B,C,R(A)) */ uvset(mrb, GETARG_C(i), GETARG_B(i), regs[GETARG_A(i)]); NEXT; } CASE(OP_JMP) { /* sBx pc+=sBx */ pc += GETARG_sBx(i); JUMP; } CASE(OP_JMPIF) { /* A sBx if R(A) pc+=sBx */ if (mrb_test(regs[GETARG_A(i)])) { pc += GETARG_sBx(i); JUMP; } NEXT; } CASE(OP_JMPNOT) { /* A sBx if R(A) pc+=sBx */ if (!mrb_test(regs[GETARG_A(i)])) { pc += GETARG_sBx(i); JUMP; } NEXT; } CASE(OP_ONERR) { /* sBx pc+=sBx on exception */ if (mrb->rsize <= mrb->ci->ridx) { if (mrb->rsize == 0) mrb->rsize = 16; else mrb->rsize *= 2; mrb->rescue = mrb_realloc(mrb, mrb->rescue, sizeof(mrb_code*) * mrb->rsize); } mrb->rescue[mrb->ci->ridx++] = pc + GETARG_sBx(i); NEXT; } CASE(OP_RESCUE) { /* A R(A) := exc; clear(exc) */ SET_OBJ_VALUE(regs[GETARG_A(i)],mrb->exc); mrb->exc = 0; NEXT; } CASE(OP_POPERR) { int a = GETARG_A(i); while (a--) { mrb->ci->ridx--; } NEXT; } CASE(OP_RAISE) { /* A raise(R(A)) */ mrb->exc = mrb_object(regs[GETARG_A(i)]); goto L_RAISE; } CASE(OP_EPUSH) { /* Bx ensure_push(SEQ[Bx]) */ struct RProc *p; p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]); /* push ensure_stack */ if (mrb->esize <= mrb->ci->eidx) { if (mrb->esize == 0) mrb->esize = 16; else mrb->esize *= 2; mrb->ensure = mrb_realloc(mrb, mrb->ensure, sizeof(struct RProc*) * mrb->esize); } mrb->ensure[mrb->ci->eidx++] = p; NEXT; } CASE(OP_EPOP) { /* A A.times{ensure_pop().call} */ int n; int a = GETARG_A(i); for (n=0; n<a; n++) { ecall(mrb, --mrb->ci->eidx); } NEXT; } L_SEND: CASE(OP_SEND) { /* A B C R(A) := call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */ int a = GETARG_A(i); int n = GETARG_C(i); struct RProc *m; struct RClass *c; mrb_callinfo *ci; mrb_value recv; mrb_sym mid = syms[GETARG_B(i)]; recv = regs[a]; c = mrb_class(mrb, recv); m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); regs[a+1] = sym; n++; } } /* push callinfo */ ci = cipush(mrb); ci->mid = mid; ci->proc = m; ci->stackidx = mrb->stack - mrb->stbase; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; ci->target_class = m->target_class; ci->pc = pc + 1; /* prepare stack */ mrb->stack += a; if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb->arena_idx = ai; if (mrb->exc) goto L_RAISE; /* pop stackpos */ mrb->stack = mrb->stbase + ci->stackidx; cipop(mrb); NEXT; } else { /* fill callinfo */ ci->acc = a; /* setup environment for calling method */ proc = mrb->ci->proc = m; irep = m->body.irep; pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; JUMP; } } CASE(OP_FSEND) { /* A B C R(A) := fcall(R(A),Sym(B),R(A+1),... ,R(A+C)) */ NEXT; } CASE(OP_VSEND) { /* A B R(A) := vcall(R(A),Sym(B)) */ NEXT; } CASE(OP_CALL) { /* A R(A) := self.call(frame.argc, frame.argv) */ mrb_callinfo *ci; mrb_value recv = mrb->stack[0]; struct RProc *m = mrb_proc_ptr(recv); /* replace callinfo */ ci = mrb->ci; ci->target_class = m->target_class; ci->proc = m; if (m->env) { ci->mid = m->env->mid; if (!m->env->stack) { m->env->stack = mrb->stack; } } /* prepare stack */ if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb->arena_idx = ai; if (mrb->exc) goto L_RAISE; /* pop stackpos */ regs = mrb->stack = mrb->stbase + ci->stackidx; cipop(mrb); NEXT; } else { /* setup environment for calling method */ proc = m; irep = m->body.irep; pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; regs[0] = m->env->stack[0]; pc = m->body.irep->iseq; JUMP; } } CASE(OP_SUPER) { /* A B C R(A) := super(R(A+1),... ,R(A+C-1)) */ mrb_value recv; mrb_callinfo *ci = mrb->ci; struct RProc *m; struct RClass *c; mrb_sym mid = ci->mid; int a = GETARG_A(i); int n = GETARG_C(i); recv = regs[0]; c = mrb->ci->proc->target_class->super; m = mrb_method_search_vm(mrb, &c, mid); if (!m) { c = mrb->ci->proc->target_class; mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); regs[a+1] = mrb_symbol_value(ci->mid); n++; } } /* push callinfo */ ci = cipush(mrb); ci->mid = mid; ci->proc = m; ci->stackidx = mrb->stack - mrb->stbase; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; ci->target_class = m->target_class; ci->pc = pc + 1; /* prepare stack */ mrb->stack += a; mrb->stack[0] = recv; if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb->arena_idx = ai; if (mrb->exc) goto L_RAISE; /* pop stackpos */ mrb->stack = mrb->stbase + ci->stackidx; cipop(mrb); NEXT; } else { /* fill callinfo */ ci->acc = a; /* setup environment for calling method */ ci->proc = m; irep = m->body.irep; pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; JUMP; } } CASE(OP_ARGARY) { /* A Bx R(A) := argument array (16=6:1:5:4) */ int a = GETARG_A(i); int bx = GETARG_Bx(i); int m1 = (bx>>10)&0x3f; int r = (bx>>9)&0x1; int m2 = (bx>>4)&0x1f; int lv = (bx>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; else { struct REnv *e = uvenv(mrb, lv-1); stack = e->stack + 1; } if (r == 0) { regs[a] = mrb_ary_new_elts(mrb, m1+m2, stack); } else { mrb_value *pp; struct RArray *rest; int len = 0; if (stack[m1].tt == MRB_TT_ARRAY) { struct RArray *ary = mrb_ary_ptr(stack[m1]); pp = ary->buf; len = ary->len; } regs[a] = mrb_ary_new_capa(mrb, m1+len+m2); rest = mrb_ary_ptr(regs[a]); memcpy(rest->buf, stack, sizeof(mrb_value)*m1); if (len > 0) { memcpy(rest->buf+m1, pp, sizeof(mrb_value)*len); } if (m2 > 0) { memcpy(rest->buf+m1+len, stack+m1+1, sizeof(mrb_value)*m2); } rest->len = m1+len+m2; } regs[a+1] = stack[m1+r+m2]; NEXT; } CASE(OP_ENTER) { /* Ax arg setup according to flags (24=5:5:1:5:5:1:1) */ /* number of optional arguments times OP_JMP should follow */ int ax = GETARG_Ax(i); int m1 = (ax>>18)&0x1f; int o = (ax>>13)&0x1f; int r = (ax>>12)&0x1; int m2 = (ax>>7)&0x1f; /* unused int k = (ax>>2)&0x1f; int kd = (ax>>1)&0x1; int b = (ax>>0)& 0x1; */ int argc = mrb->ci->argc; mrb_value *argv = regs+1; int len = m1 + o + r + m2; if (argc < 0) { struct RArray *ary = mrb_ary_ptr(regs[1]); argv = ary->buf; argc = ary->len; regs[len+2] = regs[1]; /* save argary in register */ } if (mrb->ci->proc && MRB_PROC_STRICT_P(mrb->ci->proc)) { if (argc >= 0) { if (argc < m1 + m2 || (r == 0 && argc > len)) { fprintf(stderr, "'%s': wrong number of arguments (%d for %d)\n", mrb_sym2name(mrb, mrb->ci->mid), mrb->ci->argc, m1+m2); exit(1); } } } else if (len > 1 && argc == 1 && argv[0].tt == MRB_TT_ARRAY) { argc = mrb_ary_ptr(argv[0])->len; argv = mrb_ary_ptr(argv[0])->buf; } mrb->ci->argc = len; if (argc < len) { regs[len+1] = argv[argc]; /* move block */ memmove(®s[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */ memmove(®s[len-m2+1], &argv[argc-m2], sizeof(mrb_value)*m2); /* m2 */ if (r) { /* r */ regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } pc += argc - m1 - m2 + 1; } else { memmove(®s[1], argv, sizeof(mrb_value)*(m1+o)); /* m1 + o */ if (r) { /* r */ regs[m1+o+1] = mrb_ary_new_elts(mrb, argc-m1-o-m2, argv+m1+o); } memmove(®s[m1+o+r+1], &argv[argc-m2], sizeof(mrb_value)*m2); regs[len+1] = argv[argc]; /* move block */ pc += o + 1; } JUMP; } CASE(OP_KARG) { /* A B C R(A) := kdict[Sym(B)]; if C kdict.rm(Sym(B)) */ /* if C == 2; raise unless kdict.empty? */ /* OP_JMP should follow to skip init code */ NEXT; } CASE(OP_KDICT) { /* A C R(A) := kdict */ NEXT; } CASE(OP_RETURN) { /* A return R(A) */ L_RETURN: if (mrb->ci->env) { struct REnv *e = mrb->ci->env; int len = (int)e->flags; mrb_value *p = mrb_malloc(mrb, sizeof(mrb_value)*len); e->cioff = -1; memcpy(p, e->stack, sizeof(mrb_value)*len); e->stack = p; } if (mrb->exc) { mrb_callinfo *ci; L_RAISE: ci = mrb->ci; if (ci == mrb->cibase) goto L_STOP; while (ci[0].ridx == ci[-1].ridx) { cipop(mrb); ci = mrb->ci; if (ci == mrb->cibase) { if (ci->ridx == 0) goto L_STOP; break; } } irep = ci->proc->body.irep; pool = irep->pool; syms = irep->syms; regs = mrb->stack = mrb->stbase + ci->stackidx; pc = mrb->rescue[--ci->ridx]; } else { mrb_callinfo *ci = mrb->ci; int acc, eidx = mrb->ci->eidx; mrb_value v = regs[GETARG_A(i)]; switch (GETARG_B(i)) { case OP_R_NORMAL: ci = mrb->ci; break; case OP_R_BREAK: if (proc->env->cioff < 0) { localjump_error(mrb, "break"); goto L_RAISE; } ci = mrb->ci = mrb->cibase + proc->env->cioff + 1; break; case OP_R_RETURN: if (proc->env->cioff < 0) { localjump_error(mrb, "return"); } ci = mrb->ci = mrb->cibase + proc->env->cioff; break; default: /* cannot happen */ break; } cipop(mrb); acc = ci->acc; pc = ci->pc; regs = mrb->stack = mrb->stbase + ci->stackidx; while (eidx > mrb->ci->eidx) { ecall(mrb, --eidx); } if (acc < 0) { mrb->jmp = prev_jmp; return v; } DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid))); proc = mrb->ci->proc; irep = proc->body.irep; pool = irep->pool; syms = irep->syms; regs[acc] = v; } JUMP; } CASE(OP_TAILCALL) { /* A B C return call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */ int a = GETARG_A(i); int n = GETARG_C(i); struct RProc *m; struct RClass *c; mrb_callinfo *ci; mrb_value recv; mrb_sym mid = syms[GETARG_B(i)]; recv = regs[a]; c = mrb_class(mrb, recv); m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); regs[a+1] = sym; n++; } } /* replace callinfo */ mrb->ci = ci = &mrb->ci[-1]; ci->mid = mid; ci->target_class = m->target_class; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; /* move stack */ memmove(mrb->stack, ®s[a], (ci->argc+1)*sizeof(mrb_value)); if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb->arena_idx = ai; goto L_RETURN; } else { /* setup environment for calling method */ irep = m->body.irep; pool = irep->pool; syms = irep->syms; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; } JUMP; } CASE(OP_BLKPUSH) { /* A Bx R(A) := block (16=6:1:5:4) */ int a = GETARG_A(i); int bx = GETARG_Bx(i); int m1 = (bx>>10)&0x3f; int r = (bx>>9)&0x1; int m2 = (bx>>4)&0x1f; int lv = (bx>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; else { struct REnv *e = uvenv(mrb, lv-1); stack = e->stack + 1; } regs[a] = stack[m1+r+m2]; NEXT; } #define TYPES2(a,b) (((((int)(a))<<8)|((int)(b)))&0xffff) #define OP_MATH_BODY(op,v1,v2) do {\ regs[a].value.v1 = regs[a].value.v1 op regs[a+1].value.v2;\ } while(0) #define OP_MATH(op) do {\ int a = GETARG_A(i);\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\ OP_MATH_BODY(op,i,i); \ break;\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\ {\ mrb_int x = regs[a].value.i;\ mrb_float y = regs[a+1].value.f;\ SET_FLOAT_VALUE(regs[a], (mrb_float)x op y);\ }\ break;\ case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\ OP_MATH_BODY(op,f,i);\ break;\ case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\ OP_MATH_BODY(op,f,f);\ break;\ default:\ i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));\ goto L_SEND;\ }\ } while (0) CASE(OP_ADD) { /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ int a = GETARG_A(i); switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): OP_MATH_BODY(+,i,i); break; case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): { mrb_int x = regs[a].value.i; mrb_float y = regs[a+1].value.f; SET_FLOAT_VALUE(regs[a], (mrb_float)x + y); } break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): OP_MATH_BODY(+,f,i); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): OP_MATH_BODY(+,f,f); break; case TYPES2(MRB_TT_STRING,MRB_TT_STRING): regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); break; default: i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i)); goto L_SEND; } NEXT; } CASE(OP_SUB) { /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ OP_MATH(-); NEXT; } CASE(OP_MUL) { /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ OP_MATH(*); NEXT; } CASE(OP_DIV) { /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ OP_MATH(/); NEXT; } CASE(OP_ADDI) { /* A B C R(A) := R(A)+C (Syms[B]=:+)*/ int a = GETARG_A(i); /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: regs[a].value.i += GETARG_C(i); break; case MRB_TT_FLOAT: regs[a].value.f += GETARG_C(i); break; default: SET_INT_VALUE(regs[a+1], GETARG_C(i)); i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); goto L_SEND; } NEXT; } CASE(OP_SUBI) { /* A B C R(A) := R(A)-C (Syms[B]=:+)*/ int a = GETARG_A(i); /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: regs[a].value.i -= GETARG_C(i); break; case MRB_TT_FLOAT: regs[a].value.f -= GETARG_C(i); break; default: SET_INT_VALUE(regs[a+1], GETARG_C(i)); i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); goto L_SEND; } NEXT; } #define OP_CMP_BODY(op,v1,v2) do {\ if (regs[a].value.v1 op regs[a+1].value.v2) {\ SET_TRUE_VALUE(regs[a]);\ }\ else {\ SET_FALSE_VALUE(regs[a]);\ }\ } while(0) #define OP_CMP(op) do {\ int a = GETARG_A(i);\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\ OP_CMP_BODY(op,i,i); \ break;\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\ OP_CMP_BODY(op,i,f);\ break;\ case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\ OP_CMP_BODY(op,f,i);\ break;\ case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\ OP_CMP_BODY(op,f,f);\ break;\ default:\ i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));\ goto L_SEND;\ }\ } while (0) CASE(OP_EQ) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(==); NEXT; } CASE(OP_LT) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(<); NEXT; } CASE(OP_LE) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(<=); NEXT; } CASE(OP_GT) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(>); NEXT; } CASE(OP_GE) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(>=); NEXT; } CASE(OP_ARRAY) { /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ int b = GETARG_B(i); int lim = b+GETARG_C(i); mrb_value ary = mrb_ary_new_capa(mrb, GETARG_C(i)); while (b < lim) { mrb_ary_push(mrb, ary, regs[b++]); } regs[GETARG_A(i)] = ary; NEXT; } CASE(OP_ARYCAT) { /* A B mrb_ary_concat(R(A),R(B)) */ mrb_ary_concat(mrb, regs[GETARG_A(i)], mrb_ary_splat(mrb, regs[GETARG_B(i)])); NEXT; } CASE(OP_ARYPUSH) { /* A B R(A).push(R(B)) */ mrb_ary_push(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]); NEXT; } CASE(OP_AREF) { /* A B C R(A) := R(B)[C] */ int a = GETARG_A(i); int c = GETARG_C(i); mrb_value v = regs[GETARG_B(i)]; if (v.tt != MRB_TT_ARRAY) { if (c == 0) { regs[GETARG_A(i)] = v; } else { SET_NIL_VALUE(regs[a]); } } else { regs[GETARG_A(i)] = mrb_ary_ref(mrb, v, c); } NEXT; } CASE(OP_ASET) { /* A B C R(B)[C] := R(A) */ mrb_ary_set(mrb, regs[GETARG_B(i)], GETARG_C(i), regs[GETARG_A(i)]); NEXT; } CASE(OP_APOST) { /* A B C *R(A),R(A+1)..R(A+C) := R(A) */ int a = GETARG_A(i); mrb_value v = regs[a]; int pre = GETARG_B(i); int post = GETARG_C(i); if (v.tt != MRB_TT_ARRAY) { regs[a++] = mrb_ary_new_capa(mrb, 0); while (post--) { SET_NIL_VALUE(regs[a]); a++; } } else { struct RArray *ary = mrb_ary_ptr(v); size_t len = ary->len; int i; if (len > pre + post) { regs[a++] = mrb_ary_new_elts(mrb, len - pre - post, ary->buf+pre); while (post--) { regs[a++] = ary->buf[len-post-1]; } } else { regs[a++] = mrb_ary_new_capa(mrb, 0); for (i=0; i+pre<len; i++) { regs[a+i] = ary->buf[pre+i]; } while (i < post) { SET_NIL_VALUE(regs[a+i]); i++; } } } NEXT; } CASE(OP_STRING) { /* A Bx R(A) := str_new(Lit(Bx)) */ regs[GETARG_A(i)] = mrb_str_literal(mrb, pool[GETARG_Bx(i)]); NEXT; } CASE(OP_STRCAT) { /* A B R(A).concat(R(B)) */ mrb_str_concat(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]); NEXT; } CASE(OP_HASH) { /* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ int b = GETARG_B(i); int c = GETARG_C(i); int lim = b+c*2; mrb_value hash = mrb_hash_new_capa(mrb, c); while (b < lim) { mrb_hash_set(mrb, hash, regs[b], regs[b+1]); b+=2; } regs[GETARG_A(i)] = hash; NEXT; } CASE(OP_LAMBDA) { /* A b c R(A) := lambda(SEQ[b],c) (b:c = 14:2) */ struct RProc *p; int c = GETARG_c(i); if (c & OP_L_CAPTURE) { p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]); } else { p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]); } if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT; regs[GETARG_A(i)] = mrb_obj_value(p); NEXT; } CASE(OP_OCLASS) { /* A R(A) := ::Object */ regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class); NEXT; } CASE(OP_CLASS) { /* A B R(A) := newclass(R(A),Sym(B),R(A+1)) */ struct RClass *c = 0; int a = GETARG_A(i); mrb_value base, super; mrb_sym id = syms[GETARG_B(i)]; base = regs[a]; super = regs[a+1]; if (mrb_nil_p(base)) { base = mrb_obj_value(mrb->ci->target_class); } c = mrb_vm_define_class(mrb, base, super, id); regs[a] = mrb_obj_value(c); NEXT; } CASE(OP_MODULE) { /* A B R(A) := newmodule(R(A),Sym(B)) */ struct RClass *c = 0; int a = GETARG_A(i); mrb_value base; mrb_sym id = syms[GETARG_B(i)]; base = regs[a]; if (mrb_nil_p(base)) { base = mrb_obj_value(mrb->ci->target_class); } c = mrb_vm_define_module(mrb, base, id); regs[a] = mrb_obj_value(c); NEXT; } CASE(OP_EXEC) { /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ int a = GETARG_A(i); mrb_callinfo *ci; mrb_value recv = regs[a]; struct RProc *p; /* prepare stack */ ci = cipush(mrb); ci->pc = pc + 1; ci->acc = a; ci->mid = 0; ci->stackidx = mrb->stack - mrb->stbase; ci->argc = 0; ci->target_class = mrb_class_ptr(regs[GETARG_A(i)]); p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]); p->target_class = ci->target_class; ci->proc = p; if (MRB_PROC_CFUNC_P(p)) { mrb->stack[0] = p->body.func(mrb, recv); mrb->arena_idx = ai; if (mrb->exc) goto L_RAISE; /* pop stackpos */ regs = mrb->stack = mrb->stbase + ci->stackidx; cipop(mrb); NEXT; } else { /* setup environment for calling method */ irep = p->body.irep; pool = irep->pool; syms = irep->syms; mrb->stack += a; stack_extend(mrb, irep->nregs, 1); regs = mrb->stack; pc = irep->iseq; JUMP; } } CASE(OP_METHOD) { /* A B R(A).newmethod(Sym(B),R(A+1)) */ int a = GETARG_A(i); struct RClass *c = mrb_class_ptr(regs[a]); mrb_define_method_vm(mrb, c, syms[GETARG_B(i)], regs[a+1]); NEXT; } CASE(OP_SCLASS) { /* A B R(A) := R(B).singleton_class */ regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]); NEXT; } CASE(OP_TCLASS) { /* A B R(A) := target_class */ regs[GETARG_A(i)] = mrb_obj_value(mrb->ci->target_class); NEXT; } CASE(OP_RANGE) { /* A B C R(A) := range_new(R(B),R(B+1),C) */ int b = GETARG_B(i); regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); NEXT; } CASE(OP_DEBUG) { /* A debug print R(A),R(B),R(C) */ printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i)); NEXT; } CASE(OP_STOP) { /* stop VM */ L_STOP: mrb->jmp = prev_jmp; return mrb_nil_value(); } CASE(OP_ERR) { /* Bx raise RuntimeError with message Lit(Bx) */ mrb_value msg = pool[GETARG_Bx(i)]; mrb_value exc = mrb_exc_new3(mrb, mrb->eRuntimeError_class, msg); mrb->exc = mrb_object(exc); goto L_RAISE; } } END_DISPACTH; }
static void patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) { int i; mrb_code c; int argc = irep_argc(irep); for (i = 0; i < irep->ilen; i++) { c = irep->iseq[i]; switch(GET_OPCODE(c)){ case OP_EPUSH: patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top); break; case OP_LAMBDA: { int arg_c = GETARG_c(c); if (arg_c & OP_L_CAPTURE) { patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top); } } break; case OP_SEND: if (GETARG_C(c) != 0) { break; } else { mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; } } break; case OP_MOVE: /* src part */ if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) { mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; } } /* dst part */ if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) { mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg; } } break; case OP_GETUPVAR: { int lev = GETARG_C(c)+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg; } } } break; case OP_SETUPVAR: { int lev = GETARG_C(c)+1; mrb_irep *tmp = search_irep(top, bnest, lev, irep); if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) { mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest); if (arg != 0) { /* must replace */ irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg; } } } break; case OP_STOP: if (mrb->c->ci->acc >= 0) { irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL); } break; } } }
mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { /* assert(mrb_proc_cfunc_p(proc)) */ mrb_irep *irep = proc->body.irep; mrb_code *pc = irep->iseq; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; mrb_value *regs = NULL; mrb_code i; int ai = mrb->arena_idx; jmp_buf *prev_jmp = mrb->jmp; jmp_buf c_jmp; #ifdef DIRECT_THREADED static void *optable[] = { &&L_OP_NOP, &&L_OP_MOVE, &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL, &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF, &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL, &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV, &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST, &&L_OP_GETUPVAR, &&L_OP_SETUPVAR, &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT, &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP, &&L_OP_SEND, &&L_OP_FSEND, &&L_OP_VSEND, &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER, &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH, &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST, &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH, &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS, &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC, &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS, &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR, }; #endif if (setjmp(c_jmp) == 0) { mrb->jmp = &c_jmp; } else { goto L_RAISE; } if (!mrb->stack) { stack_init(mrb); } mrb->ci->proc = proc; mrb->ci->nregs = irep->nregs + 2; regs = mrb->stack; INIT_DISPATCH { CASE(OP_NOP) { /* do nothing */ NEXT; } CASE(OP_MOVE) { /* A B R(A) := R(B) */ #if 0 regs[GETARG_A(i)] = regs[GETARG_B(i)]; #elif 1 int a = GETARG_A(i); int b = GETARG_B(i); regs[a].tt = regs[b].tt; regs[a].value = regs[b].value; #else memcpy(regs+GETARG_A(i), regs+GETARG_B(i), sizeof(mrb_value)); #endif NEXT; } CASE(OP_LOADL) { /* A Bx R(A) := Pool(Bx) */ regs[GETARG_A(i)] = pool[GETARG_Bx(i)]; NEXT; } CASE(OP_LOADI) { /* A Bx R(A) := sBx */ SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i)); NEXT; } CASE(OP_LOADSYM) { /* A B R(A) := Sym(B) */ SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]); NEXT; } CASE(OP_LOADNIL) { /* A B R(A) := nil */ int a = GETARG_A(i); SET_NIL_VALUE(regs[a]); NEXT; } CASE(OP_LOADSELF) { /* A R(A) := self */ regs[GETARG_A(i)] = mrb->stack[0]; NEXT; } CASE(OP_LOADT) { /* A R(A) := true */ regs[GETARG_A(i)] = mrb_true_value(); NEXT; } CASE(OP_LOADF) { /* A R(A) := false */ regs[GETARG_A(i)] = mrb_false_value(); NEXT; } CASE(OP_GETGLOBAL) { /* A B R(A) := getglobal(Sym(B)) */ regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETGLOBAL) { /* setglobal(Sym(b), R(A)) */ mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETSPECIAL) { /* A Bx R(A) := Special[Bx] */ regs[GETARG_A(i)] = mrb_vm_special_get(mrb, GETARG_Bx(i)); NEXT; } CASE(OP_SETSPECIAL) { /* A Bx Special[Bx] := R(A) */ mrb_vm_special_set(mrb, GETARG_Bx(i), regs[GETARG_A(i)]); NEXT; } CASE(OP_GETIV) { /* A Bx R(A) := ivget(Bx) */ regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETIV) { /* ivset(Sym(B),R(A)) */ mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETCV) { /* A B R(A) := ivget(Sym(B)) */ regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETCV) { /* ivset(Sym(B),R(A)) */ mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETCONST) { /* A B R(A) := constget(Sym(B)) */ regs[GETARG_A(i)] = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETCONST) { /* A B constset(Sym(B),R(A)) */ mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETMCNST) { /* A B C R(A) := R(C)::Sym(B) */ int a = GETARG_A(i); regs[a] = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETMCNST) { /* A B C R(A+1)::Sym(B) := R(A) */ int a = GETARG_A(i); mrb_const_set(mrb, regs[a+1], syms[GETARG_Bx(i)], regs[a]); NEXT; } CASE(OP_GETUPVAR) { /* A B C R(A) := uvget(B,C) */ regs[GETARG_A(i)] = uvget(mrb, GETARG_C(i), GETARG_B(i)); NEXT; } CASE(OP_SETUPVAR) { /* A B C uvset(B,C,R(A)) */ uvset(mrb, GETARG_C(i), GETARG_B(i), regs[GETARG_A(i)]); NEXT; } CASE(OP_JMP) { /* sBx pc+=sBx */ pc += GETARG_sBx(i); JUMP; } CASE(OP_JMPIF) { /* A sBx if R(A) pc+=sBx */ if (mrb_test(regs[GETARG_A(i)])) { pc += GETARG_sBx(i); JUMP; } NEXT; } CASE(OP_JMPNOT) { /* A sBx if R(A) pc+=sBx */ if (!mrb_test(regs[GETARG_A(i)])) { pc += GETARG_sBx(i); JUMP; } NEXT; } CASE(OP_ONERR) { /* sBx pc+=sBx on exception */ if (mrb->rsize <= mrb->ci->ridx) { if (mrb->rsize == 0) mrb->rsize = 16; else mrb->rsize *= 2; mrb->rescue = mrb_realloc(mrb, mrb->rescue, sizeof(mrb_code*) * mrb->rsize); } mrb->rescue[mrb->ci->ridx++] = pc + GETARG_sBx(i); NEXT; } CASE(OP_RESCUE) { /* A R(A) := exc; clear(exc) */ SET_OBJ_VALUE(regs[GETARG_A(i)],mrb->exc); mrb->exc = 0; NEXT; } CASE(OP_POPERR) { int a = GETARG_A(i); while (a--) { mrb->ci->ridx--; } NEXT; } CASE(OP_RAISE) { /* A raise(R(A)) */ mrb->exc = (struct RObject*)mrb_object(regs[GETARG_A(i)]); goto L_RAISE; } CASE(OP_EPUSH) { /* Bx ensure_push(SEQ[Bx]) */ struct RProc *p; p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]); /* push ensure_stack */ if (mrb->esize <= mrb->ci->eidx) { if (mrb->esize == 0) mrb->esize = 16; else mrb->esize *= 2; mrb->ensure = mrb_realloc(mrb, mrb->ensure, sizeof(struct RProc*) * mrb->esize); } mrb->ensure[mrb->ci->eidx++] = p; NEXT; } CASE(OP_EPOP) { /* A A.times{ensure_pop().call} */ int n; int a = GETARG_A(i); for (n=0; n<a; n++) { ecall(mrb, --mrb->ci->eidx); } NEXT; } L_SEND: CASE(OP_SEND) { /* A B C R(A) := call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */ int a = GETARG_A(i); int n = GETARG_C(i); struct RProc *m; struct RClass *c; mrb_callinfo *ci; mrb_value recv; mrb_sym mid = syms[GETARG_B(i)]; recv = regs[a]; c = mrb_class(mrb, recv); m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); regs[a+1] = sym; n++; } } /* push callinfo */ ci = cipush(mrb); ci->mid = mid; ci->proc = m; ci->stackidx = mrb->stack - mrb->stbase; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; ci->target_class = m->target_class; ci->pc = pc + 1; ci->acc = a; /* prepare stack */ mrb->stack += a; if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb->arena_idx = ai; if (mrb->exc) goto L_RAISE; /* pop stackpos */ mrb->stack = mrb->stbase + ci->stackidx; cipop(mrb); NEXT; } else { /* setup environment for calling method */ proc = mrb->ci->proc = m; irep = m->body.irep; pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; JUMP; } } CASE(OP_FSEND) { /* A B C R(A) := fcall(R(A),Sym(B),R(A+1),... ,R(A+C)) */ NEXT; } CASE(OP_VSEND) { /* A B R(A) := vcall(R(A),Sym(B)) */ NEXT; } CASE(OP_CALL) { /* A R(A) := self.call(frame.argc, frame.argv) */ mrb_callinfo *ci; mrb_value recv = mrb->stack[0]; struct RProc *m = mrb_proc_ptr(recv); /* replace callinfo */ ci = mrb->ci; ci->target_class = m->target_class; ci->proc = m; if (m->env) { if (m->env->mid) { ci->mid = m->env->mid; } if (!m->env->stack) { m->env->stack = mrb->stack; } } /* prepare stack */ if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb->arena_idx = ai; if (mrb->exc) goto L_RAISE; /* pop stackpos */ regs = mrb->stack = mrb->stbase + ci->stackidx; cipop(mrb); NEXT; } else { /* setup environment for calling method */ proc = m; irep = m->body.irep; if (!irep) { mrb->stack[0] = mrb_nil_value(); goto L_RETURN; } pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; regs[0] = m->env->stack[0]; pc = m->body.irep->iseq; JUMP; } } CASE(OP_SUPER) { /* A B C R(A) := super(R(A+1),... ,R(A+C-1)) */ mrb_value recv; mrb_callinfo *ci = mrb->ci; struct RProc *m; struct RClass *c; mrb_sym mid = ci->mid; int a = GETARG_A(i); int n = GETARG_C(i); recv = regs[0]; c = mrb->ci->proc->target_class->super; m = mrb_method_search_vm(mrb, &c, mid); if (!m) { c = mrb->ci->proc->target_class; mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); regs[a+1] = mrb_symbol_value(ci->mid); n++; } } /* push callinfo */ ci = cipush(mrb); ci->mid = mid; ci->proc = m; ci->stackidx = mrb->stack - mrb->stbase; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; ci->target_class = m->target_class; ci->pc = pc + 1; /* prepare stack */ mrb->stack += a; mrb->stack[0] = recv; if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb->arena_idx = ai; if (mrb->exc) goto L_RAISE; /* pop stackpos */ mrb->stack = mrb->stbase + ci->stackidx; cipop(mrb); NEXT; } else { /* fill callinfo */ ci->acc = a; /* setup environment for calling method */ ci->proc = m; irep = m->body.irep; pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; JUMP; } } CASE(OP_ARGARY) { /* A Bx R(A) := argument array (16=6:1:5:4) */ int a = GETARG_A(i); int bx = GETARG_Bx(i); int m1 = (bx>>10)&0x3f; int r = (bx>>9)&0x1; int m2 = (bx>>4)&0x1f; int lv = (bx>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; else { struct REnv *e = uvenv(mrb, lv-1); if (!e) { mrb_value exc; const char *m = "super called outside of method"; exc = mrb_exc_new(mrb, E_NOMETHOD_ERROR, m, strlen(m)); mrb->exc = (struct RObject*)mrb_object(exc); goto L_RAISE; } stack = e->stack + 1; } if (r == 0) { regs[a] = mrb_ary_new_elts(mrb, m1+m2, stack); } else { mrb_value *pp = NULL; struct RArray *rest; int len = 0; if (stack[m1].tt == MRB_TT_ARRAY) { struct RArray *ary = mrb_ary_ptr(stack[m1]); pp = ary->ptr; len = ary->len; } regs[a] = mrb_ary_new_capa(mrb, m1+len+m2); rest = mrb_ary_ptr(regs[a]); memcpy(rest->ptr, stack, sizeof(mrb_value)*m1); if (len > 0) { memcpy(rest->ptr+m1, pp, sizeof(mrb_value)*len); } if (m2 > 0) { memcpy(rest->ptr+m1+len, stack+m1+1, sizeof(mrb_value)*m2); } rest->len = m1+len+m2; } regs[a+1] = stack[m1+r+m2]; NEXT; } CASE(OP_ENTER) { /* Ax arg setup according to flags (24=5:5:1:5:5:1:1) */ /* number of optional arguments times OP_JMP should follow */ int ax = GETARG_Ax(i); int m1 = (ax>>18)&0x1f; int o = (ax>>13)&0x1f; int r = (ax>>12)&0x1; int m2 = (ax>>7)&0x1f; /* unused int k = (ax>>2)&0x1f; int kd = (ax>>1)&0x1; int b = (ax>>0)& 0x1; */ int argc = mrb->ci->argc; mrb_value *argv = regs+1; int len = m1 + o + r + m2; mrb_value *blk = &argv[argc < 0 ? 1 : argc]; if (argc < 0) { struct RArray *ary = mrb_ary_ptr(regs[1]); argv = ary->ptr; argc = ary->len; mrb_gc_protect(mrb, regs[1]); } if (mrb->ci->proc && MRB_PROC_STRICT_P(mrb->ci->proc)) { if (argc >= 0) { if (argc < m1 + m2 || (r == 0 && argc > len)) { argnum_error(mrb, m1+m2); goto L_RAISE; } } } else if (len > 1 && argc == 1 && argv[0].tt == MRB_TT_ARRAY) { argc = mrb_ary_ptr(argv[0])->len; argv = mrb_ary_ptr(argv[0])->ptr; } mrb->ci->argc = len; if (argc < len) { regs[len+1] = *blk; /* move block */ memmove(®s[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */ memmove(®s[len-m2+1], &argv[argc-m2], sizeof(mrb_value)*m2); /* m2 */ if (r) { /* r */ regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } if (o == 0) pc++; else pc += argc - m1 - m2 + 1; } else { memmove(®s[1], argv, sizeof(mrb_value)*(m1+o)); /* m1 + o */ if (r) { /* r */ regs[m1+o+1] = mrb_ary_new_elts(mrb, argc-m1-o-m2, argv+m1+o); } memmove(®s[m1+o+r+1], &argv[argc-m2], sizeof(mrb_value)*m2); regs[len+1] = *blk; /* move block */ pc += o + 1; } JUMP; } CASE(OP_KARG) { /* A B C R(A) := kdict[Sym(B)]; if C kdict.rm(Sym(B)) */ /* if C == 2; raise unless kdict.empty? */ /* OP_JMP should follow to skip init code */ NEXT; } CASE(OP_KDICT) { /* A C R(A) := kdict */ NEXT; } CASE(OP_RETURN) { /* A return R(A) */ L_RETURN: if (mrb->exc) { mrb_callinfo *ci; int eidx; L_RAISE: ci = mrb->ci; eidx = mrb->ci->eidx; if (ci == mrb->cibase) goto L_STOP; while (ci[0].ridx == ci[-1].ridx) { cipop(mrb); ci = mrb->ci; if (ci->acc < 0) { mrb->jmp = prev_jmp; longjmp(*(jmp_buf*)mrb->jmp, 1); } while (eidx > mrb->ci->eidx) { ecall(mrb, --eidx); } if (ci == mrb->cibase) { if (ci->ridx == 0) { mrb->stack = mrb->stbase; goto L_STOP; } break; } } irep = ci->proc->body.irep; pool = irep->pool; syms = irep->syms; regs = mrb->stack = mrb->stbase + ci[1].stackidx; pc = mrb->rescue[--ci->ridx]; } else { mrb_callinfo *ci = mrb->ci; int acc, eidx = mrb->ci->eidx; mrb_value v = regs[GETARG_A(i)]; switch (GETARG_B(i)) { case OP_R_NORMAL: if (ci == mrb->cibase) { localjump_error(mrb, "return"); goto L_RAISE; } ci = mrb->ci; break; case OP_R_BREAK: if (proc->env->cioff < 0) { localjump_error(mrb, "break"); goto L_RAISE; } ci = mrb->ci = mrb->cibase + proc->env->cioff + 1; break; case OP_R_RETURN: if (proc->env->cioff < 0) { localjump_error(mrb, "return"); goto L_RAISE; } ci = mrb->ci = mrb->cibase + proc->env->cioff; break; default: /* cannot happen */ break; } cipop(mrb); acc = ci->acc; pc = ci->pc; regs = mrb->stack = mrb->stbase + ci->stackidx; while (eidx > mrb->ci->eidx) { ecall(mrb, --eidx); } if (acc < 0) { mrb->jmp = prev_jmp; return v; } DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid))); proc = mrb->ci->proc; irep = proc->body.irep; pool = irep->pool; syms = irep->syms; regs[acc] = v; } JUMP; } CASE(OP_TAILCALL) { /* A B C return call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */ int a = GETARG_A(i); int n = GETARG_C(i); struct RProc *m; struct RClass *c; mrb_callinfo *ci; mrb_value recv; mrb_sym mid = syms[GETARG_B(i)]; recv = regs[a]; c = mrb_class(mrb, recv); m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); regs[a+1] = sym; n++; } } /* replace callinfo */ mrb->ci = ci = &mrb->ci[-1]; ci->mid = mid; ci->target_class = m->target_class; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; /* move stack */ memmove(mrb->stack, ®s[a], (ci->argc+1)*sizeof(mrb_value)); if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb->arena_idx = ai; goto L_RETURN; } else { /* setup environment for calling method */ irep = m->body.irep; pool = irep->pool; syms = irep->syms; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; } JUMP; } CASE(OP_BLKPUSH) { /* A Bx R(A) := block (16=6:1:5:4) */ int a = GETARG_A(i); int bx = GETARG_Bx(i); int m1 = (bx>>10)&0x3f; int r = (bx>>9)&0x1; int m2 = (bx>>4)&0x1f; int lv = (bx>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; else { struct REnv *e = uvenv(mrb, lv-1); if (!e) { localjump_error(mrb, "yield"); goto L_RAISE; } stack = e->stack + 1; } regs[a] = stack[m1+r+m2]; NEXT; } #define TYPES2(a,b) (((((int)(a))<<8)|((int)(b)))&0xffff) #define OP_MATH_BODY(op,v1,v2) do {\ regs[a].value.v1 = regs[a].value.v1 op regs[a+1].value.v2;\ } while(0) #define OP_MATH(op,iop,s) do {\ int a = GETARG_A(i);\ /* need to check if op is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\ regs[a] = iop(mrb, regs[a], regs[a+1]);\ break;\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\ {\ mrb_int x = regs[a].value.i;\ mrb_float y = regs[a+1].value.f;\ SET_FLOAT_VALUE(regs[a], (mrb_float)x op y);\ }\ break;\ case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\ OP_MATH_BODY(op,f,i);\ break;\ case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\ OP_MATH_BODY(op,f,f);\ break;\ s\ default:\ i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));\ goto L_SEND;\ }\ } while (0) CASE(OP_ADD) { /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ OP_MATH(+,mrb_fixnum_plus, case TYPES2(MRB_TT_STRING,MRB_TT_STRING): regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); break;); NEXT; } CASE(OP_SUB) { /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ OP_MATH(-,mrb_fixnum_minus,;); NEXT; } CASE(OP_MUL) { /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ OP_MATH(*,mrb_fixnum_mul,;); NEXT; }
int luaU_guess_locals(Proto* f, int main) { int blockend[255]; int block; int regassign[MAXARG_A]; int regusage[MAXARG_A]; int regblock[MAXARG_A]; int lastfree; int i,i2,x,y,pc; llist list_begin; llist* list_next = &list_begin; if (f->lineinfo != NULL) { return 0; } if (f->sizelocvars>0) { return 0; } list_begin.next = NULL; block = 0; lastfree = 0; blockend[block] = f->sizecode-1; for (i=0; i<f->maxstacksize; i++) { regassign[i] = 0; regusage[i] = 0; regblock[i] = 0; } // parameters, varargs, nil optimizations for (i = 0; i < f->numparams; i++) { list_next = add(list_next,0,blockend[block]); regassign[lastfree] = 0; regusage[lastfree] = 1; regblock[lastfree] = blockend[block]; lastfree++; } if ((f->is_vararg==7) || ((f->is_vararg&2))) { if (main!=0) { list_next = add(list_next,0,blockend[block]); lastfree++; regassign[lastfree] = 0; regusage[lastfree] = 1; regblock[lastfree] = blockend[block]; lastfree++; } } { Instruction i = f->code[0]; OpCode o = GET_OPCODE(i); int a = GETARG_A(i); if ((o == OP_SETGLOBAL) || (o == OP_SETUPVAL)) { int ixx; for (ixx = lastfree; ixx <= a; ixx++) { if (ixx!=a) { list_next = add(list_next,0,blockend[block]); lastfree++; } regassign[lastfree] = 0; regusage[lastfree] = 1; regblock[lastfree] = blockend[block]; lastfree++; } } else if (o != OP_JMP) { int ixx; for (ixx = lastfree; ixx <= a-1; ixx++) { list_next = add(list_next,0,blockend[block]); lastfree++; regassign[lastfree] = 0; regusage[lastfree] = 1; regblock[lastfree] = blockend[block]; lastfree++; } } } // start code checking for (pc = 0; pc < f->sizecode; pc++) { Instruction instr = f->code[pc]; OpCode o = GET_OPCODE(instr); int a = GETARG_A(instr); int b = GETARG_B(instr); int c = GETARG_C(instr); int bc = GETARG_Bx(instr); int sbc = GETARG_sBx(instr); int dest = 0; int setreg = -1; int setregto = -1; int setreg2 = -1; int loadreg = -1; int loadreg2 = -1; int loadreg3 = -1; int loadregto = -1; int intlocfrom = -1; int intlocto = -1; if ((o==OP_JMP) || (o==OP_FORPREP)) { dest = pc + sbc + 2; } else if ((pc+1!=f->sizecode) && (GET_OPCODE(f->code[pc+1])==OP_JMP)) { dest = pc+1+GETARG_sBx(f->code[pc+1])+2; } // check which registers were read or written to. switch (o) { case OP_MOVE: setreg = a; if (b<=a) { intlocfrom = b; intlocto = b; } loadreg = b; break; case OP_UNM: case OP_NOT: case OP_LEN: setreg = a; loadreg = b; break; case OP_LOADNIL: setreg = a; setregto = b; break; case OP_LOADK: case OP_GETUPVAL: case OP_GETGLOBAL: case OP_LOADBOOL: case OP_NEWTABLE: case OP_CLOSURE: setreg = a; break; case OP_GETTABLE: setreg = a; loadreg = b; if (!IS_CONSTANT(c)) { loadreg2 = c; } break; case OP_SETGLOBAL: case OP_SETUPVAL: loadreg = a; break; case OP_SETTABLE: loadreg = a; if (!IS_CONSTANT(b)) { loadreg2 = b; } if (!IS_CONSTANT(c)) { if (loadreg2==-1) { loadreg2 = c; } else { loadreg3 = c; } if ((a+1!=c) && (c>a)) { intlocto = c-1; } } intlocfrom = 0; if (a-1>=intlocto) { intlocto = a-1; } break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_POW: case OP_MOD: setreg = a; if (!IS_CONSTANT(b)) { loadreg = b; } if (!IS_CONSTANT(c)) { if (loadreg==-1) { loadreg = c; } else { loadreg2 = c; } } break; case OP_CONCAT: setreg = a; loadreg = b; loadregto = c; break; case OP_CALL: if (c==0) { setreg = a; setregto = f->maxstacksize; } else if (c>=2) { setreg = a; setregto = a+c-2; } else if (c==1) { intlocfrom = 0; intlocto = a-1; } if (b==0) { loadreg = a; loadregto = f->maxstacksize; } else { loadreg = a; loadregto = a+b-1; } break; case OP_RETURN: if (b==0) { loadreg = a; loadregto = f->maxstacksize; } else if (b>=2) { loadreg = a; loadregto = a+b-2; } break; case OP_TAILCALL: if (b==0) { loadreg = a; loadregto = f->maxstacksize; } else { loadreg = a; loadregto = a+b-1; } break; case OP_VARARG: if (b==0) { setreg = a; setregto = f->maxstacksize; } else { setreg = a; setregto = a+b-1; } break; case OP_SELF: setreg = a; setregto = a+1; loadreg = b; if (a>b) { intlocfrom = 0; intlocto = b; } if (!IS_CONSTANT(c)) { loadreg2 = c; } break; case OP_EQ: case OP_LT: case OP_LE: if (!IS_CONSTANT(b)) { loadreg = b; } if (!IS_CONSTANT(c)) { if (loadreg==-1) { loadreg = c; } else { loadreg2 = c; } } break; case OP_TEST: loadreg = a; break; case OP_TESTSET: setreg = a; loadreg = b; break; case OP_SETLIST: loadreg = a; if (b==0) { loadregto = f->maxstacksize; } else { loadregto = a+b; } break; case OP_FORLOOP: break; case OP_TFORLOOP: break; case OP_FORPREP: loadreg = a; loadregto = a+2; setreg = a; setregto = a+3; intlocfrom = a; intlocto = a+3; regassign[a] = pc; regassign[a+1] = pc; regassign[a+2] = pc; regassign[a+3] = pc+1; regblock[a] = dest; regblock[a+1] = dest; regblock[a+2] = dest; regblock[a+3] = dest-1; block++; blockend[block] = dest-1; if (GET_OPCODE(f->code[dest-2])==OP_JMP) { blockend[block]--; } break; case OP_JMP: if (GET_OPCODE(f->code[dest-1]) == OP_TFORLOOP) { int a = GETARG_A(f->code[dest-1]); int c = GETARG_C(f->code[dest-1]); setreg = a; setregto = a+c+2; loadreg = a; loadregto = a+2; intlocfrom = a; intlocto = a+c+2; regassign[a] = pc; regassign[a+1] = pc; regassign[a+2] = pc; regblock[a] = dest+1; regblock[a+1] = dest+1; regblock[a+2] = dest+1; for (x=a+3;x<=a+c+2;x++) { regassign[x] = pc+1; regblock[x] = dest-1; } } if (dest>pc) { block++; blockend[block] = dest-1; } if (GET_OPCODE(f->code[dest-2])==OP_JMP) { blockend[block]--; } break; case OP_CLOSE: default: break; } for (i=1; i<=block; i++) { x = blockend[i]; i2 = i-1; while ((i2>=0) && (blockend[i2]<x)) { blockend[i2+1] = blockend[i2]; i2 = i2-1; } blockend[i2+1] = x; } if (loadreg!=-1) { if (loadregto==-1) loadregto = loadreg; for (i=loadreg;i<=loadregto;i++) { regusage[i]--; } if (loadreg2!=-1) regusage[loadreg2]--; if (loadreg3!=-1) regusage[loadreg3]--; } if (setreg!=-1) { if (setregto==-1) setregto = setreg; for (i=setreg;i<=setregto;i++) { regusage[i]++; } if (setreg2!=-1) regusage[setreg2]++; } i2 = lastfree-1; for (i=lastfree; i<f->maxstacksize; i++) { if ((regusage[i]<0) || (regusage[i]>1)) { i2 = i; } if ((intlocfrom!=-1) && ((intlocfrom<=i) && (i<=intlocto))) { i2 = i; } } for (i=setreg; i<=setregto; i++) { if (i>i2) { regassign[i] = pc+1; regblock[i] = blockend[block]; } } for (i=lastfree; i<=i2; i++) { //fprintf(stderr,"%d %d %d %d\n",i,regassign[i],regblock[i],block); list_next = add(list_next,regassign[i],regblock[i]); lastfree++; } while (blockend[block] <= pc+1) { block--; } while ((lastfree!=0) && (regblock[lastfree-1] <= pc+1)) { lastfree--; regusage[lastfree]=0; } } // print out information { int length = 0; llist* list = &list_begin; while (list->next!=NULL) { length++; list = list->next; } f->sizelocvars = length; if (f->sizelocvars>0) { f->locvars = luaM_newvector(glstate,f->sizelocvars,LocVar); list = &list_begin; length = 0; while (list->next != NULL) { char names[10]; sprintf(names,"l_%d_%d",main,length); f->locvars[length].varname = luaS_new(glstate, names); f->locvars[length].startpc = list->startpc; f->locvars[length].endpc = list->endpc; length++; list = list->next; } } } deletellist(list_begin.next); // run with all functions for (i=0; i<f->sizep; i++) { luaU_guess_locals(f->p[i],main+i+1); } return 1; }
static void PrintCode(const Proto* f) { const Instruction* code=f->code; int pc,n=f->sizecode; for (pc=0; pc<n; pc++) { Instruction i=code[pc]; OpCode o=GET_OPCODE(i); int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); int bc=GETARG_Bx(i); int sbc=GETARG_sBx(i); int line=getline(f,pc); #if 0 printf("%0*lX",Sizeof(i)*2,i); #endif printf("\t%d\t",pc+1); if (line>0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); switch (getOpMode(o)) { case iABC: printf("%d %d %d",a,b,c); break; case iABx: printf("%d %d",a,bc); break; case iAsBx: printf("%d %d",a,sbc); break; } switch (o) { case OP_LOADK: printf("\t; "); PrintConstant(f,bc); break; case OP_GETUPVAL: case OP_SETUPVAL: printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-"); break; case OP_GETGLOBAL: case OP_SETGLOBAL: printf("\t; %s",svalue(&f->k[bc])); break; case OP_GETTABLE: case OP_SELF: if (c>=MAXSTACK) { printf("\t; "); PrintConstant(f,c-MAXSTACK); } break; case OP_SETTABLE: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_POW: case OP_EQ: case OP_LT: case OP_LE: if (b>=MAXSTACK || c>=MAXSTACK) { printf("\t; "); if (b>=MAXSTACK) PrintConstant(f,b-MAXSTACK); else printf("-"); printf(" "); if (c>=MAXSTACK) PrintConstant(f,c-MAXSTACK); } break; case OP_JMP: case OP_FORLOOP: case OP_TFORPREP: printf("\t; to %d",sbc+pc+2); break; case OP_CLOSURE: printf("\t; %p",VOID(f->p[bc])); break; default: break; } printf("\n"); } }
mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { /* assert(mrb_proc_cfunc_p(proc)) */ mrb_irep *irep = proc->body.irep; mrb_code *pc = irep->iseq; mrb_value *pool = irep->pool; mrb_sym *syms = irep->syms; mrb_value *regs = NULL; mrb_code i; int ai = mrb_gc_arena_save(mrb); jmp_buf *prev_jmp = (jmp_buf *)mrb->jmp; jmp_buf c_jmp; #ifdef DIRECT_THREADED static void *optable[] = { &&L_OP_NOP, &&L_OP_MOVE, &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL, &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF, &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL, &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV, &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST, &&L_OP_GETUPVAR, &&L_OP_SETUPVAR, &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT, &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP, &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND, &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER, &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH, &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST, &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH, &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS, &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC, &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS, &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR, }; #endif if (setjmp(c_jmp) == 0) { mrb->jmp = &c_jmp; } else { goto L_RAISE; } if (!mrb->stack) { stack_init(mrb); } mrb->ci->proc = proc; mrb->ci->nregs = irep->nregs + 2; regs = mrb->stack; regs[0] = self; INIT_DISPATCH { CASE(OP_NOP) { /* do nothing */ NEXT; } CASE(OP_MOVE) { /* A B R(A) := R(B) */ regs[GETARG_A(i)] = regs[GETARG_B(i)]; NEXT; } CASE(OP_LOADL) { /* A Bx R(A) := Pool(Bx) */ regs[GETARG_A(i)] = pool[GETARG_Bx(i)]; NEXT; } CASE(OP_LOADI) { /* A Bx R(A) := sBx */ SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i)); NEXT; } CASE(OP_LOADSYM) { /* A B R(A) := Sym(B) */ SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]); NEXT; } CASE(OP_LOADSELF) { /* A R(A) := self */ regs[GETARG_A(i)] = regs[0]; NEXT; } CASE(OP_LOADT) { /* A R(A) := true */ SET_TRUE_VALUE(regs[GETARG_A(i)]); NEXT; } CASE(OP_LOADF) { /* A R(A) := false */ SET_FALSE_VALUE(regs[GETARG_A(i)]); NEXT; } CASE(OP_GETGLOBAL) { /* A B R(A) := getglobal(Sym(B)) */ regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETGLOBAL) { /* setglobal(Sym(b), R(A)) */ mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETSPECIAL) { /* A Bx R(A) := Special[Bx] */ regs[GETARG_A(i)] = mrb_vm_special_get(mrb, GETARG_Bx(i)); NEXT; } CASE(OP_SETSPECIAL) { /* A Bx Special[Bx] := R(A) */ mrb_vm_special_set(mrb, GETARG_Bx(i), regs[GETARG_A(i)]); NEXT; } CASE(OP_GETIV) { /* A Bx R(A) := ivget(Bx) */ regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETIV) { /* ivset(Sym(B),R(A)) */ mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETCV) { /* A B R(A) := ivget(Sym(B)) */ regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETCV) { /* ivset(Sym(B),R(A)) */ mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETCONST) { /* A B R(A) := constget(Sym(B)) */ regs[GETARG_A(i)] = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETCONST) { /* A B constset(Sym(B),R(A)) */ mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]); NEXT; } CASE(OP_GETMCNST) { /* A B C R(A) := R(C)::Sym(B) */ int a = GETARG_A(i); regs[a] = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]); NEXT; } CASE(OP_SETMCNST) { /* A B C R(A+1)::Sym(B) := R(A) */ int a = GETARG_A(i); mrb_const_set(mrb, regs[a+1], syms[GETARG_Bx(i)], regs[a]); NEXT; } CASE(OP_GETUPVAR) { /* A B C R(A) := uvget(B,C) */ regs[GETARG_A(i)] = uvget(mrb, GETARG_C(i), GETARG_B(i)); NEXT; } CASE(OP_SETUPVAR) { /* A B C uvset(B,C,R(A)) */ uvset(mrb, GETARG_C(i), GETARG_B(i), regs[GETARG_A(i)]); NEXT; } CASE(OP_JMP) { /* sBx pc+=sBx */ pc += GETARG_sBx(i); JUMP; } CASE(OP_JMPIF) { /* A sBx if R(A) pc+=sBx */ if (mrb_test(regs[GETARG_A(i)])) { pc += GETARG_sBx(i); JUMP; } NEXT; } CASE(OP_JMPNOT) { /* A sBx if R(A) pc+=sBx */ if (!mrb_test(regs[GETARG_A(i)])) { pc += GETARG_sBx(i); JUMP; } NEXT; } CASE(OP_ONERR) { /* sBx pc+=sBx on exception */ if (mrb->rsize <= mrb->ci->ridx) { if (mrb->rsize == 0) mrb->rsize = 16; else mrb->rsize *= 2; mrb->rescue = (mrb_code **)mrb_realloc(mrb, mrb->rescue, sizeof(mrb_code*) * mrb->rsize); } mrb->rescue[mrb->ci->ridx++] = pc + GETARG_sBx(i); NEXT; } CASE(OP_RESCUE) { /* A R(A) := exc; clear(exc) */ SET_OBJ_VALUE(regs[GETARG_A(i)], mrb->exc); mrb->exc = 0; NEXT; } CASE(OP_POPERR) { int a = GETARG_A(i); while (a--) { mrb->ci->ridx--; } NEXT; } CASE(OP_RAISE) { /* A raise(R(A)) */ mrb->exc = (struct RObject*)mrb_object(regs[GETARG_A(i)]); goto L_RAISE; } CASE(OP_EPUSH) { /* Bx ensure_push(SEQ[Bx]) */ struct RProc *p; p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]); /* push ensure_stack */ if (mrb->esize <= mrb->ci->eidx) { if (mrb->esize == 0) mrb->esize = 16; else mrb->esize *= 2; mrb->ensure = (struct RProc **)mrb_realloc(mrb, mrb->ensure, sizeof(struct RProc*) * mrb->esize); } mrb->ensure[mrb->ci->eidx++] = p; mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_EPOP) { /* A A.times{ensure_pop().call} */ int n; int a = GETARG_A(i); for (n=0; n<a; n++) { ecall(mrb, --mrb->ci->eidx); } mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_LOADNIL) { /* A B R(A) := nil */ int a = GETARG_A(i); SET_NIL_VALUE(regs[a]); NEXT; } CASE(OP_SENDB) { /* fall through */ }; L_SEND: CASE(OP_SEND) { /* A B C R(A) := call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */ int a = GETARG_A(i); int n = GETARG_C(i); struct RProc *m; struct RClass *c; mrb_callinfo *ci; mrb_value recv, result; mrb_sym mid = syms[GETARG_B(i)]; recv = regs[a]; if (GET_OPCODE(i) != OP_SENDB) { if (n == CALL_MAXARGS) { SET_NIL_VALUE(regs[a+2]); } else { SET_NIL_VALUE(regs[a+n+1]); } } c = mrb_class(mrb, recv); m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); regs[a+1] = sym; n++; } } /* push callinfo */ ci = cipush(mrb); ci->mid = mid; ci->proc = m; ci->stackidx = mrb->stack - mrb->stbase; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; ci->target_class = c; ci->pc = pc + 1; ci->acc = a; /* prepare stack */ mrb->stack += a; if (MRB_PROC_CFUNC_P(m)) { if (n == CALL_MAXARGS) { ci->nregs = 3; } else { ci->nregs = n + 2; } result = m->body.func(mrb, recv); mrb->stack[0] = result; mrb_gc_arena_restore(mrb, ai); if (mrb->exc) goto L_RAISE; /* pop stackpos */ regs = mrb->stack = mrb->stbase + mrb->ci->stackidx; cipop(mrb); NEXT; } else { /* setup environment for calling method */ proc = mrb->ci->proc = m; irep = m->body.irep; pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; JUMP; } } CASE(OP_FSEND) { /* A B C R(A) := fcall(R(A),Sym(B),R(A+1),... ,R(A+C)) */ NEXT; } CASE(OP_CALL) { /* A R(A) := self.call(frame.argc, frame.argv) */ mrb_callinfo *ci; mrb_value recv = mrb->stack[0]; struct RProc *m = mrb_proc_ptr(recv); /* replace callinfo */ ci = mrb->ci; ci->target_class = m->target_class; ci->proc = m; if (m->env) { if (m->env->mid) { ci->mid = m->env->mid; } if (!m->env->stack) { m->env->stack = mrb->stack; } } /* prepare stack */ if (MRB_PROC_CFUNC_P(m)) { recv = m->body.func(mrb, recv); mrb_gc_arena_restore(mrb, ai); if (mrb->exc) goto L_RAISE; /* pop stackpos */ ci = mrb->ci; regs = mrb->stack = mrb->stbase + ci->stackidx; regs[ci->acc] = recv; pc = ci->pc; cipop(mrb); irep = mrb->ci->proc->body.irep; pool = irep->pool; syms = irep->syms; JUMP; } else { /* setup environment for calling method */ proc = m; irep = m->body.irep; if (!irep) { mrb->stack[0] = mrb_nil_value(); goto L_RETURN; } pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; regs[0] = m->env->stack[0]; pc = m->body.irep->iseq; JUMP; } } CASE(OP_SUPER) { /* A B C R(A) := super(R(A+1),... ,R(A+C-1)) */ mrb_value recv; mrb_callinfo *ci = mrb->ci; struct RProc *m; struct RClass *c; mrb_sym mid = ci->mid; int a = GETARG_A(i); int n = GETARG_C(i); recv = regs[0]; c = mrb->ci->target_class->super; m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); SET_SYM_VALUE(regs[a+1], ci->mid); n++; } } /* push callinfo */ ci = cipush(mrb); ci->mid = mid; ci->proc = m; ci->stackidx = mrb->stack - mrb->stbase; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; ci->target_class = m->target_class; ci->pc = pc + 1; /* prepare stack */ mrb->stack += a; mrb->stack[0] = recv; if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb_gc_arena_restore(mrb, ai); if (mrb->exc) goto L_RAISE; /* pop stackpos */ regs = mrb->stack = mrb->stbase + mrb->ci->stackidx; cipop(mrb); NEXT; } else { /* fill callinfo */ ci->acc = a; /* setup environment for calling method */ ci->proc = m; irep = m->body.irep; pool = irep->pool; syms = irep->syms; ci->nregs = irep->nregs; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; JUMP; } } CASE(OP_ARGARY) { /* A Bx R(A) := argument array (16=6:1:5:4) */ int a = GETARG_A(i); int bx = GETARG_Bx(i); int m1 = (bx>>10)&0x3f; int r = (bx>>9)&0x1; int m2 = (bx>>4)&0x1f; int lv = (bx>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; else { struct REnv *e = uvenv(mrb, lv-1); if (!e) { mrb_value exc; static const char m[] = "super called outside of method"; exc = mrb_exc_new(mrb, E_NOMETHOD_ERROR, m, sizeof(m) - 1); mrb->exc = (struct RObject*)mrb_object(exc); goto L_RAISE; } stack = e->stack + 1; } if (r == 0) { regs[a] = mrb_ary_new_elts(mrb, m1+m2, stack); } else { mrb_value *pp = NULL; struct RArray *rest; int len = 0; if (mrb_array_p(stack[m1])) { struct RArray *ary = mrb_ary_ptr(stack[m1]); pp = ary->ptr; len = ary->len; } regs[a] = mrb_ary_new_capa(mrb, m1+len+m2); rest = mrb_ary_ptr(regs[a]); stack_copy(rest->ptr, stack, m1); if (len > 0) { stack_copy(rest->ptr+m1, pp, len); } if (m2 > 0) { stack_copy(rest->ptr+m1+len, stack+m1+1, m2); } rest->len = m1+len+m2; } regs[a+1] = stack[m1+r+m2]; mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_ENTER) { /* Ax arg setup according to flags (24=5:5:1:5:5:1:1) */ /* number of optional arguments times OP_JMP should follow */ int ax = GETARG_Ax(i); int m1 = (ax>>18)&0x1f; int o = (ax>>13)&0x1f; int r = (ax>>12)&0x1; int m2 = (ax>>7)&0x1f; /* unused int k = (ax>>2)&0x1f; int kd = (ax>>1)&0x1; int b = (ax>>0)& 0x1; */ int argc = mrb->ci->argc; mrb_value *argv = regs+1; mrb_value *argv0 = argv; int len = m1 + o + r + m2; mrb_value *blk = &argv[argc < 0 ? 1 : argc]; if (argc < 0) { struct RArray *ary = mrb_ary_ptr(regs[1]); argv = ary->ptr; argc = ary->len; mrb_gc_protect(mrb, regs[1]); } if (mrb->ci->proc && MRB_PROC_STRICT_P(mrb->ci->proc)) { if (argc >= 0) { if (argc < m1 + m2 || (r == 0 && argc > len)) { argnum_error(mrb, m1+m2); goto L_RAISE; } } } else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) { argc = mrb_ary_ptr(argv[0])->len; argv = mrb_ary_ptr(argv[0])->ptr; } mrb->ci->argc = len; if (argc < len) { regs[len+1] = *blk; /* move block */ if (argv0 != argv) { memmove(®s[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */ } if (m2) { memmove(®s[len-m2+1], &argv[argc-m2], sizeof(mrb_value)*m2); /* m2 */ } if (r) { /* r */ regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); } if (o == 0) pc++; else pc += argc - m1 - m2 + 1; } else { if (argv0 != argv) { regs[len+1] = *blk; /* move block */ memmove(®s[1], argv, sizeof(mrb_value)*(m1+o)); /* m1 + o */ } if (r) { /* r */ regs[m1+o+1] = mrb_ary_new_elts(mrb, argc-m1-o-m2, argv+m1+o); } if (m2) { memmove(®s[m1+o+r+1], &argv[argc-m2], sizeof(mrb_value)*m2); } if (argv0 == argv) { regs[len+1] = *blk; /* move block */ } pc += o + 1; } JUMP; } CASE(OP_KARG) { /* A B C R(A) := kdict[Sym(B)]; if C kdict.rm(Sym(B)) */ /* if C == 2; raise unless kdict.empty? */ /* OP_JMP should follow to skip init code */ NEXT; } CASE(OP_KDICT) { /* A C R(A) := kdict */ NEXT; } CASE(OP_RETURN) { /* A return R(A) */ L_RETURN: if (mrb->exc) { mrb_callinfo *ci; int eidx; L_RAISE: ci = mrb->ci; mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern(mrb, "lastpc"), mrb_voidp_value(pc)); mrb_obj_iv_set(mrb, mrb->exc, mrb_intern(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->cibase)); eidx = ci->eidx; if (ci == mrb->cibase) { if (ci->ridx == 0) goto L_STOP; goto L_RESCUE; } while (ci[0].ridx == ci[-1].ridx) { cipop(mrb); ci = mrb->ci; if (ci[1].acc < 0 && prev_jmp) { mrb->jmp = prev_jmp; longjmp(*(jmp_buf*)mrb->jmp, 1); } while (eidx > mrb->ci->eidx) { ecall(mrb, --eidx); } if (ci == mrb->cibase) { if (ci->ridx == 0) { regs = mrb->stack = mrb->stbase; goto L_STOP; } break; } } L_RESCUE: irep = ci->proc->body.irep; pool = irep->pool; syms = irep->syms; regs = mrb->stack = mrb->stbase + ci[1].stackidx; pc = mrb->rescue[--ci->ridx]; } else { mrb_callinfo *ci = mrb->ci; int acc, eidx = mrb->ci->eidx; mrb_value v = regs[GETARG_A(i)]; switch (GETARG_B(i)) { case OP_R_RETURN: // Fall through to OP_R_NORMAL otherwise if (proc->env && !MRB_PROC_STRICT_P(proc)) { struct REnv *e = top_env(mrb, proc); if (e->cioff < 0) { localjump_error(mrb, "return"); goto L_RAISE; } ci = mrb->cibase + e->cioff; if (ci == mrb->cibase) { localjump_error(mrb, "return"); goto L_RAISE; } mrb->ci = ci; break; } case OP_R_NORMAL: if (ci == mrb->cibase) { localjump_error(mrb, "return"); goto L_RAISE; } ci = mrb->ci; break; case OP_R_BREAK: if (proc->env->cioff < 0) { localjump_error(mrb, "break"); goto L_RAISE; } ci = mrb->ci = mrb->cibase + proc->env->cioff + 1; break; default: /* cannot happen */ break; } cipop(mrb); acc = ci->acc; pc = ci->pc; regs = mrb->stack = mrb->stbase + ci->stackidx; while (eidx > mrb->ci->eidx) { ecall(mrb, --eidx); } if (acc < 0) { mrb->jmp = prev_jmp; return v; } DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid))); proc = mrb->ci->proc; irep = proc->body.irep; pool = irep->pool; syms = irep->syms; regs[acc] = v; } JUMP; } CASE(OP_TAILCALL) { /* A B C return call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */ int a = GETARG_A(i); int n = GETARG_C(i); struct RProc *m; struct RClass *c; mrb_callinfo *ci; mrb_value recv; mrb_sym mid = syms[GETARG_B(i)]; recv = regs[a]; c = mrb_class(mrb, recv); m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); mid = mrb_intern(mrb, "method_missing"); m = mrb_method_search_vm(mrb, &c, mid); if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } else { memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1)); regs[a+1] = sym; n++; } } /* replace callinfo */ ci = mrb->ci; ci->mid = mid; ci->target_class = m->target_class; ci->argc = n; if (ci->argc == CALL_MAXARGS) ci->argc = -1; /* move stack */ memmove(mrb->stack, ®s[a], (ci->argc+1)*sizeof(mrb_value)); if (MRB_PROC_CFUNC_P(m)) { mrb->stack[0] = m->body.func(mrb, recv); mrb_gc_arena_restore(mrb, ai); goto L_RETURN; } else { /* setup environment for calling method */ irep = m->body.irep; pool = irep->pool; syms = irep->syms; if (ci->argc < 0) { stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3); } else { stack_extend(mrb, irep->nregs, ci->argc+2); } regs = mrb->stack; pc = irep->iseq; } JUMP; } CASE(OP_BLKPUSH) { /* A Bx R(A) := block (16=6:1:5:4) */ int a = GETARG_A(i); int bx = GETARG_Bx(i); int m1 = (bx>>10)&0x3f; int r = (bx>>9)&0x1; int m2 = (bx>>4)&0x1f; int lv = (bx>>0)&0xf; mrb_value *stack; if (lv == 0) stack = regs + 1; else { struct REnv *e = uvenv(mrb, lv-1); if (!e) { localjump_error(mrb, "yield"); goto L_RAISE; } stack = e->stack + 1; } regs[a] = stack[m1+r+m2]; NEXT; } #define attr_i value.i #ifdef MRB_NAN_BOXING #define attr_f f #else #define attr_f value.f #endif #define TYPES2(a,b) (((((int)(a))<<8)|((int)(b)))&0xffff) #define OP_MATH_BODY(op,v1,v2) do {\ regs[a].v1 = regs[a].v1 op regs[a+1].v2;\ } while(0) CASE(OP_ADD) { /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/ int a = GETARG_A(i); /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): { mrb_int x, y, z; x = mrb_fixnum(regs[a]); y = mrb_fixnum(regs[a+1]); z = x + y; if (((x < 0) ^ (y < 0)) == 0 && (x < 0) != (z < 0)) { /* integer overflow */ SET_FLT_VALUE(regs[a], (mrb_float)x + (mrb_float)y); break; } SET_INT_VALUE(regs[a], z); } break; case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): { mrb_int x = mrb_fixnum(regs[a]); mrb_float y = mrb_float(regs[a+1]); SET_FLT_VALUE(regs[a], (mrb_float)x + y); } break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): OP_MATH_BODY(+,attr_f,attr_i); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): OP_MATH_BODY(+,attr_f,attr_f); break; case TYPES2(MRB_TT_STRING,MRB_TT_STRING): regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]); break; default: goto L_SEND; } mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_SUB) { /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/ int a = GETARG_A(i); /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): { mrb_int x, y, z; x = mrb_fixnum(regs[a]); y = mrb_fixnum(regs[a+1]); z = x - y; if (((x < 0) ^ (y < 0)) != 0 && (x < 0) != (z < 0)) { /* integer overflow */ SET_FLT_VALUE(regs[a], (mrb_float)x - (mrb_float)y); break; } SET_INT_VALUE(regs[a], z); } break; case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): { mrb_int x = mrb_fixnum(regs[a]); mrb_float y = mrb_float(regs[a+1]); SET_FLT_VALUE(regs[a], (mrb_float)x - y); } break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): OP_MATH_BODY(-,attr_f,attr_i); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): OP_MATH_BODY(-,attr_f,attr_f); break; default: goto L_SEND; } NEXT; } CASE(OP_MUL) { /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/ int a = GETARG_A(i); /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): { mrb_int x, y, z; x = mrb_fixnum(regs[a]); y = mrb_fixnum(regs[a+1]); z = x * y; if (x != 0 && z/x != y) { SET_FLT_VALUE(regs[a], (mrb_float)x * (mrb_float)y); } else { SET_INT_VALUE(regs[a], z); } } break; case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): { mrb_int x = mrb_fixnum(regs[a]); mrb_float y = mrb_float(regs[a+1]); SET_FLT_VALUE(regs[a], (mrb_float)x * y); } break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): OP_MATH_BODY(*,attr_f,attr_i); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): OP_MATH_BODY(*,attr_f,attr_f); break; default: goto L_SEND; } NEXT; } CASE(OP_DIV) { /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ int a = GETARG_A(i); /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): { mrb_int x = mrb_fixnum(regs[a]); mrb_int y = mrb_fixnum(regs[a+1]); SET_FLT_VALUE(regs[a], (mrb_float)x / (mrb_float)y); } break; case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): { mrb_int x = mrb_fixnum(regs[a]); mrb_float y = mrb_float(regs[a+1]); SET_FLT_VALUE(regs[a], (mrb_float)x / y); } break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): OP_MATH_BODY(/,attr_f,attr_i); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): OP_MATH_BODY(/,attr_f,attr_f); break; default: goto L_SEND; } NEXT; } CASE(OP_ADDI) { /* A B C R(A) := R(A)+C (Syms[B]=:+)*/ int a = GETARG_A(i); /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: { mrb_int x = regs[a].attr_i; mrb_int y = GETARG_C(i); mrb_int z = x + y; if (((x < 0) ^ (y < 0)) == 0 && (x < 0) != (z < 0)) { /* integer overflow */ SET_FLT_VALUE(regs[a], (mrb_float)x + (mrb_float)y); break; } regs[a].attr_i = z; } break; case MRB_TT_FLOAT: regs[a].attr_f += GETARG_C(i); break; default: SET_INT_VALUE(regs[a+1], GETARG_C(i)); i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); goto L_SEND; } NEXT; } CASE(OP_SUBI) { /* A B C R(A) := R(A)-C (Syms[B]=:+)*/ int a = GETARG_A(i); /* need to check if + is overridden */ switch (mrb_type(regs[a])) { case MRB_TT_FIXNUM: { mrb_int x = regs[a].attr_i; mrb_int y = GETARG_C(i); mrb_int z = x - y; if (((x < 0) ^ (y < 0)) != 0 && (x < 0) != (z < 0)) { /* integer overflow */ SET_FLT_VALUE(regs[a], (mrb_float)x - (mrb_float)y); break; } regs[a].attr_i = z; } break; case MRB_TT_FLOAT: regs[a].attr_f -= GETARG_C(i); break; default: SET_INT_VALUE(regs[a+1], GETARG_C(i)); i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1); goto L_SEND; } NEXT; } #define OP_CMP_BODY(op,v1,v2) do {\ if (regs[a].v1 op regs[a+1].v2) {\ SET_TRUE_VALUE(regs[a]);\ }\ else {\ SET_FALSE_VALUE(regs[a]);\ }\ } while(0) #define OP_CMP(op) do {\ int a = GETARG_A(i);\ /* need to check if - is overridden */\ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\ OP_CMP_BODY(op,attr_i,attr_i);\ break;\ case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\ OP_CMP_BODY(op,attr_i,attr_f);\ break;\ case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\ OP_CMP_BODY(op,attr_f,attr_i);\ break;\ case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\ OP_CMP_BODY(op,attr_f,attr_f);\ break;\ default:\ goto L_SEND;\ }\ } while (0) CASE(OP_EQ) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ int a = GETARG_A(i); if (mrb_obj_eq(mrb, regs[a], regs[a+1])) { SET_TRUE_VALUE(regs[a]); } else { OP_CMP(==); } NEXT; } CASE(OP_LT) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(<); NEXT; } CASE(OP_LE) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(<=); NEXT; } CASE(OP_GT) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(>); NEXT; } CASE(OP_GE) { /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/ OP_CMP(>=); NEXT; } CASE(OP_ARRAY) { /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */ regs[GETARG_A(i)] = mrb_ary_new_from_values(mrb, GETARG_C(i), ®s[GETARG_B(i)]); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_ARYCAT) { /* A B mrb_ary_concat(R(A),R(B)) */ mrb_ary_concat(mrb, regs[GETARG_A(i)], mrb_ary_splat(mrb, regs[GETARG_B(i)])); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_ARYPUSH) { /* A B R(A).push(R(B)) */ mrb_ary_push(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]); NEXT; } CASE(OP_AREF) { /* A B C R(A) := R(B)[C] */ int a = GETARG_A(i); int c = GETARG_C(i); mrb_value v = regs[GETARG_B(i)]; if (!mrb_array_p(v)) { if (c == 0) { regs[GETARG_A(i)] = v; } else { SET_NIL_VALUE(regs[a]); } } else { regs[GETARG_A(i)] = mrb_ary_ref(mrb, v, c); } NEXT; } CASE(OP_ASET) { /* A B C R(B)[C] := R(A) */ mrb_ary_set(mrb, regs[GETARG_B(i)], GETARG_C(i), regs[GETARG_A(i)]); NEXT; } CASE(OP_APOST) { /* A B C *R(A),R(A+1)..R(A+C) := R(A) */ int a = GETARG_A(i); mrb_value v = regs[a]; int pre = GETARG_B(i); int post = GETARG_C(i); if (!mrb_array_p(v)) { regs[a++] = mrb_ary_new_capa(mrb, 0); while (post--) { SET_NIL_VALUE(regs[a]); a++; } } else { struct RArray *ary = mrb_ary_ptr(v); int len = ary->len; int i; if (len > pre + post) { regs[a++] = mrb_ary_new_elts(mrb, len - pre - post, ary->ptr+pre); while (post--) { regs[a++] = ary->ptr[len-post-1]; } } else { regs[a++] = mrb_ary_new_capa(mrb, 0); for (i=0; i+pre<len; i++) { regs[a+i] = ary->ptr[pre+i]; } while (i < post) { SET_NIL_VALUE(regs[a+i]); i++; } } } mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_STRING) { /* A Bx R(A) := str_new(Lit(Bx)) */ regs[GETARG_A(i)] = mrb_str_literal(mrb, pool[GETARG_Bx(i)]); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_STRCAT) { /* A B R(A).concat(R(B)) */ mrb_str_concat(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]); NEXT; } CASE(OP_HASH) { /* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */ int b = GETARG_B(i); int c = GETARG_C(i); int lim = b+c*2; mrb_value hash = mrb_hash_new_capa(mrb, c); while (b < lim) { mrb_hash_set(mrb, hash, regs[b], regs[b+1]); b+=2; } regs[GETARG_A(i)] = hash; mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_LAMBDA) { /* A b c R(A) := lambda(SEQ[b],c) (b:c = 14:2) */ struct RProc *p; int c = GETARG_c(i); if (c & OP_L_CAPTURE) { p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]); } else { p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]); } if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT; regs[GETARG_A(i)] = mrb_obj_value(p); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_OCLASS) { /* A R(A) := ::Object */ regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class); NEXT; } CASE(OP_CLASS) { /* A B R(A) := newclass(R(A),Sym(B),R(A+1)) */ struct RClass *c = 0; int a = GETARG_A(i); mrb_value base, super; mrb_sym id = syms[GETARG_B(i)]; base = regs[a]; super = regs[a+1]; if (mrb_nil_p(base)) { base = mrb_obj_value(mrb->ci->target_class); } c = mrb_vm_define_class(mrb, base, super, id); regs[a] = mrb_obj_value(c); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_MODULE) { /* A B R(A) := newmodule(R(A),Sym(B)) */ struct RClass *c = 0; int a = GETARG_A(i); mrb_value base; mrb_sym id = syms[GETARG_B(i)]; base = regs[a]; if (mrb_nil_p(base)) { base = mrb_obj_value(mrb->ci->target_class); } c = mrb_vm_define_module(mrb, base, id); regs[a] = mrb_obj_value(c); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_EXEC) { /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */ int a = GETARG_A(i); mrb_callinfo *ci; mrb_value recv = regs[a]; struct RProc *p; /* prepare stack */ ci = cipush(mrb); ci->pc = pc + 1; ci->acc = a; ci->mid = 0; ci->stackidx = mrb->stack - mrb->stbase; ci->argc = 0; ci->target_class = mrb_class_ptr(recv); /* prepare stack */ mrb->stack += a; p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]); p->target_class = ci->target_class; ci->proc = p; if (MRB_PROC_CFUNC_P(p)) { mrb->stack[0] = p->body.func(mrb, recv); mrb_gc_arena_restore(mrb, ai); if (mrb->exc) goto L_RAISE; /* pop stackpos */ regs = mrb->stack = mrb->stbase + mrb->ci->stackidx; cipop(mrb); NEXT; } else { irep = p->body.irep; pool = irep->pool; syms = irep->syms; stack_extend(mrb, irep->nregs, 1); ci->nregs = irep->nregs; regs = mrb->stack; pc = irep->iseq; JUMP; } } CASE(OP_METHOD) { /* A B R(A).newmethod(Sym(B),R(A+1)) */ int a = GETARG_A(i); struct RClass *c = mrb_class_ptr(regs[a]); mrb_define_method_vm(mrb, c, syms[GETARG_B(i)], regs[a+1]); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_SCLASS) { /* A B R(A) := R(B).singleton_class */ regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_TCLASS) { /* A B R(A) := target_class */ if (!mrb->ci->target_class) { static const char msg[] = "no target class or module"; mrb_value exc = mrb_exc_new(mrb, E_TYPE_ERROR, msg, sizeof(msg) - 1); mrb->exc = (struct RObject*)mrb_object(exc); goto L_RAISE; } regs[GETARG_A(i)] = mrb_obj_value(mrb->ci->target_class); NEXT; } CASE(OP_RANGE) { /* A B C R(A) := range_new(R(B),R(B+1),C) */ int b = GETARG_B(i); regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); mrb_gc_arena_restore(mrb, ai); NEXT; } CASE(OP_DEBUG) { /* A debug print R(A),R(B),R(C) */ #ifdef ENABLE_STDIO printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i)); #else abort(); #endif NEXT; } CASE(OP_STOP) { /* stop VM */ L_STOP: { int n = mrb->ci->eidx; while (n--) { ecall(mrb, n); } } mrb->jmp = prev_jmp; if (mrb->exc) { return mrb_obj_value(mrb->exc); } return regs[irep->nlocals]; } CASE(OP_ERR) { /* Bx raise RuntimeError with message Lit(Bx) */ mrb_value msg = pool[GETARG_Bx(i)]; mrb_value exc; if (GETARG_A(i) == 0) { exc = mrb_exc_new3(mrb, E_RUNTIME_ERROR, msg); } else { exc = mrb_exc_new3(mrb, E_LOCALJUMP_ERROR, msg); } mrb->exc = (struct RObject*)mrb_object(exc); goto L_RAISE; } } END_DISPATCH; }
static Instruction symbexec(const Proto* pt, int lastpc, int reg) { int pc; int last; /* stores position of last instruction that changed `reg' */ last = pt->sizecode - 1; /* points to final return (a `neutral' instruction) */ check(precheck(pt)); for (pc = 0; pc < lastpc; pc++) { Instruction i = pt->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); int b = 0; int c = 0; check(op < NUM_OPCODES); checkreg(pt, a); switch (getOpMode(op)) { case iABC: { b = GETARG_B(i); c = GETARG_C(i); check(checkArgMode(pt, b, getBMode(op))); check(checkArgMode(pt, c, getCMode(op))); break; } case iABx: { b = GETARG_Bx(i); if (getBMode(op) == OpArgK) check(b < pt->sizek); break; } case iAsBx: { b = GETARG_sBx(i); if (getBMode(op) == OpArgR) { int dest = pc + 1 + b; check(0 <= dest && dest < pt->sizecode); if (dest > 0) { int j; /* check that it does not jump to a setlist count; this is tricky, because the count from a previous setlist may have the same value of an invalid setlist; so, we must go all the way back to the first of them (if any) */ for (j = 0; j < dest; j++) { Instruction d = pt->code[dest - 1 - j]; if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break; } /* if 'j' is even, previous value is not a setlist (even if it looks like one) */ check((j & 1) == 0); } } break; } } if (testAMode(op)) { if (a == reg) last = pc; /* change register `a' */ } if (testTMode(op)) { check(pc + 2 < pt->sizecode); /* check skip */ check(GET_OPCODE(pt->code[pc + 1]) == OP_JMP); } switch (op) { case OP_LOADBOOL: { if (c == 1) /* does it jump? */ { check(pc + 2 < pt->sizecode); /* check its jump */ check(GET_OPCODE(pt->code[pc + 1]) != OP_SETLIST || GETARG_C(pt->code[pc + 1]) != 0); } break; } case OP_LOADNIL: { if (a <= reg && reg <= b) last = pc; /* set registers from `a' to `b' */ break; } case OP_GETUPVAL: case OP_SETUPVAL: { check(b < pt->nups); break; } case OP_GETGLOBAL: case OP_SETGLOBAL: { check(ttisstring(&pt->k[b])); break; } case OP_SELF: { checkreg(pt, a + 1); if (reg == a + 1) last = pc; break; } case OP_CONCAT: { check(b < c); /* at least two operands */ break; } case OP_TFORLOOP: { check(c >= 1); /* at least one result (control variable) */ checkreg(pt, a + 2 + c); /* space for results */ if (reg >= a + 2) last = pc; /* affect all regs above its base */ break; } case OP_FORLOOP: case OP_FORPREP: checkreg(pt, a + 3); /* go through */ case OP_JMP: { int dest = pc + 1 + b; /* not full check and jump is forward and do not skip `lastpc'? */ if (reg != NO_REG && pc < dest && dest <= lastpc) pc += b; /* do the jump */ break; } case OP_CALL: case OP_TAILCALL: { if (b != 0) { checkreg(pt, a + b - 1); } c--; /* c = num. returns */ if (c == LUA_MULTRET) { check(checkopenop(pt, pc)); } else if (c != 0) checkreg(pt, a + c - 1); if (reg >= a) last = pc; /* affect all registers above base */ break; } case OP_RETURN: { b--; /* b = num. returns */ if (b > 0) checkreg(pt, a + b - 1); break; } case OP_SETLIST: { if (b > 0) checkreg(pt, a + b); if (c == 0) { pc++; check(pc < pt->sizecode - 1); } break; } case OP_CLOSURE: { int nup, j; check(b < pt->sizep); nup = pt->p[b]->nups; check(pc + nup < pt->sizecode); for (j = 1; j <= nup; j++) { OpCode op1 = GET_OPCODE(pt->code[pc + j]); check(op1 == OP_GETUPVAL || op1 == OP_MOVE); } if (reg != NO_REG) /* tracing? */ pc += nup; /* do not 'execute' these pseudo-instructions */ break; } case OP_VARARG: { check((pt->is_vararg & VARARG_ISVARARG) && !(pt->is_vararg & VARARG_NEEDSARG)); b--; if (b == LUA_MULTRET) check(checkopenop(pt, pc)); checkreg(pt, a + b - 1); break; } default: break; } } return pt->code[last]; }
static void decode_instruction(ktap_proto *f, int instr) { int opcode = GET_OPCODE(instr); ktap_value *k; k = f->k; printf("%.8x\t", instr); printf("%s\t", ktap_opnames[opcode]); switch (opcode) { case OP_MOVE: printf("\t"); print_base(GETARG_A(instr)); printf(" <- "); print_base(GETARG_B(instr)); break; case OP_GETTABUP: print_base(GETARG_A(instr)); printf(" <- "); print_upvalue(GETARG_B(instr)); printf("{"); print_RKC(instr); printf("}"); break; case OP_GETTABLE: print_base(GETARG_A(instr)); printf(" <- "); print_base(GETARG_B(instr)); printf("{"); print_RKC(instr); printf("}"); break; case OP_SETTABLE: print_base(GETARG_A(instr)); printf("{"); print_RKB(instr); printf("}"); printf(" <- "); print_RKC(instr); break; case OP_LOADK: printf("\t"); print_base(GETARG_A(instr)); printf(" <- "); kp_showobj(NULL, k + GETARG_Bx(instr)); break; case OP_CALL: printf("\t"); print_base(GETARG_A(instr)); break; case OP_JMP: printf("\t%d", GETARG_sBx(instr)); break; case OP_CLOSURE: printf("\t"); print_base(GETARG_A(instr)); printf(" <- closure(func starts from line %d)", f->p[GETARG_Bx(instr)]->lineinfo[0]); break; case OP_SETTABUP: print_upvalue(GETARG_A(instr)); printf("{"); print_RKB(instr); printf("} <- "); print_RKC(instr); break; case OP_GETUPVAL: print_base(GETARG_A(instr)); printf(" <- "); print_upvalue(GETARG_B(instr)); break; case OP_NEWTABLE: print_base(GETARG_A(instr)); printf(" <- {}"); default: break; } printf("\n"); }
static void PrintCode(const Proto* f) { const Instruction* code=f->code; int pc,n=f->sizecode; for (pc=0; pc<n; pc++) { Instruction i=code[pc]; OpCode o=GET_OPCODE(i); int a=GETARG_A(i); int b=GETARG_B(i); int c=GETARG_C(i); int ax=GETARG_Ax(i); int bx=GETARG_Bx(i); int sbx=GETARG_sBx(i); int line=getfuncline(f,pc); printf("\t%d\t",pc+1); if (line>0) printf("[%d]\t",line); else printf("[-]\t"); printf("%-9s\t",luaP_opnames[o]); switch (getOpMode(o)) { case iABC: printf("%d",a); if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b); if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c); break; case iABx: printf("%d",a); if (getBMode(o)==OpArgK) printf(" %d",MYK(bx)); if (getBMode(o)==OpArgU) printf(" %d",bx); break; case iAsBx: printf("%d %d",a,sbx); break; case iAx: printf("%d",MYK(ax)); break; } switch (o) { case OP_LOADK: printf("\t; "); PrintConstant(f,bx); break; case OP_GETUPVAL: case OP_SETUPVAL: printf("\t; %s",UPVALNAME(b)); break; case OP_GETTABUP: printf("\t; %s",UPVALNAME(b)); if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABUP: printf("\t; %s",UPVALNAME(a)); if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); } if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); } break; case OP_GETTABLE: case OP_SELF: if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); } break; case OP_SETTABLE: case OP_ADD: case OP_SUB: case OP_MUL: case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: case OP_EQ: case OP_LT: case OP_LE: if (ISK(b) || ISK(c)) { printf("\t; "); if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-"); printf(" "); if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-"); } break; case OP_JMP: case OP_FORLOOP: case OP_FORPREP: case OP_TFORLOOP: printf("\t; to %d",sbx+pc+2); break; case OP_CLOSURE: printf("\t; %p",VOID(f->p[bx])); break; case OP_SETLIST: if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c); break; case OP_EXTRAARG: printf("\t; "); PrintConstant(f,ax); break; default: break; } printf("\n"); } }
static void codedump(mrb_state *mrb, mrb_irep *irep) { #ifndef MRB_DISABLE_STDIO int i; int ai; mrb_code c; const char *file = NULL, *next_file; int32_t line; if (!irep) return; printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen); for (i = 0; i < (int)irep->ilen; i++) { ai = mrb_gc_arena_save(mrb); next_file = mrb_debug_get_filename(irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } line = mrb_debug_get_line(irep, i); if (line < 0) { printf(" "); } else { printf("%5d ", line); } printf("%03d ", i); c = irep->iseq[i]; switch (GET_OPCODE(c)) { case OP_NOP: printf("OP_NOP\n"); break; case OP_MOVE: printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); print_lv(mrb, irep, c, RAB); break; case OP_LOADL: { mrb_value v = irep->pool[GETARG_Bx(c)]; mrb_value s = mrb_inspect(mrb, v); printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); } print_lv(mrb, irep, c, RA); break; case OP_LOADI: printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c)); print_lv(mrb, irep, c, RA); break; case OP_LOADSYM: printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); print_lv(mrb, irep, c, RA); break; case OP_LOADNIL: printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_LOADSELF: printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_LOADT: printf("OP_LOADT\tR%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_LOADF: printf("OP_LOADF\tR%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_GETGLOBAL: printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); print_lv(mrb, irep, c, RA); break; case OP_SETGLOBAL: printf("OP_SETGLOBAL\t:%s\tR%d\t", mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_GETCONST: printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); print_lv(mrb, irep, c, RA); break; case OP_SETCONST: printf("OP_SETCONST\t:%s\tR%d\t", mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_GETMCNST: printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); print_lv(mrb, irep, c, RAB); break; case OP_SETMCNST: printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1, mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_GETIV: printf("OP_GETIV\tR%d\t%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); print_lv(mrb, irep, c, RA); break; case OP_SETIV: printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_GETUPVAR: printf("OP_GETUPVAR\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); print_lv(mrb, irep, c, RA); break; case OP_SETUPVAR: printf("OP_SETUPVAR\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); print_lv(mrb, irep, c, RA); break; case OP_GETCV: printf("OP_GETCV\tR%d\t%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)])); print_lv(mrb, irep, c, RA); break; case OP_SETCV: printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]), GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_JMP: printf("OP_JMP\t%03d\n", i+GETARG_sBx(c)); break; case OP_JMPIF: printf("OP_JMPIF\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c)); break; case OP_JMPNOT: printf("OP_JMPNOT\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c)); break; case OP_SEND: printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_SENDB: printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_TAILCALL: printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_SUPER: printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c), GETARG_C(c)); break; case OP_ARGARY: printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c), (GETARG_Bx(c)>>10)&0x3f, (GETARG_Bx(c)>>9)&0x1, (GETARG_Bx(c)>>4)&0x1f, (GETARG_Bx(c)>>0)&0xf); print_lv(mrb, irep, c, RA); break; case OP_ENTER: printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", (GETARG_Ax(c)>>18)&0x1f, (GETARG_Ax(c)>>13)&0x1f, (GETARG_Ax(c)>>12)&0x1, (GETARG_Ax(c)>>7)&0x1f, (GETARG_Ax(c)>>2)&0x1f, (GETARG_Ax(c)>>1)&0x1, GETARG_Ax(c) & 0x1); break; case OP_RETURN: printf("OP_RETURN\tR%d", GETARG_A(c)); switch (GETARG_B(c)) { case OP_R_NORMAL: case OP_R_RETURN: printf("\treturn\t"); break; case OP_R_BREAK: printf("\tbreak\t"); break; default: printf("\tbroken\t"); break; break; } print_lv(mrb, irep, c, RA); break; case OP_BLKPUSH: printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c), (GETARG_Bx(c)>>10)&0x3f, (GETARG_Bx(c)>>9)&0x1, (GETARG_Bx(c)>>4)&0x1f, (GETARG_Bx(c)>>0)&0xf); print_lv(mrb, irep, c, RA); break; case OP_LAMBDA: printf("OP_LAMBDA\tR%d\tI(%+d)\t%d", GETARG_A(c), GETARG_b(c)+1, GETARG_c(c)); print_lv(mrb, irep, c, RA); break; case OP_RANGE: printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); print_lv(mrb, irep, c, RAB); break; case OP_METHOD: printf("OP_METHOD\tR%d\t:%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); print_lv(mrb, irep, c, RA); break; case OP_ADD: printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_ADDI: printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_SUB: printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_SUBI: printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_MUL: printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_DIV: printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_LT: printf("OP_LT\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_LE: printf("OP_LE\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_GT: printf("OP_GT\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_GE: printf("OP_GE\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_EQ: printf("OP_EQ\tR%d\t:%s\t%d\n", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c)); break; case OP_STOP: printf("OP_STOP\n"); break; case OP_ARRAY: printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); print_lv(mrb, irep, c, RAB); break; case OP_ARYCAT: printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); print_lv(mrb, irep, c, RAB); break; case OP_ARYPUSH: printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); print_lv(mrb, irep, c, RAB); break; case OP_AREF: printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); print_lv(mrb, irep, c, RAB); break; case OP_APOST: printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); print_lv(mrb, irep, c, RA); break; case OP_STRING: { mrb_value v = irep->pool[GETARG_Bx(c)]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s)); } print_lv(mrb, irep, c, RA); break; case OP_STRCAT: printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); print_lv(mrb, irep, c, RAB); break; case OP_HASH: printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c)); print_lv(mrb, irep, c, RAB); break; case OP_OCLASS: printf("OP_OCLASS\tR%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_CLASS: printf("OP_CLASS\tR%d\t:%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); print_lv(mrb, irep, c, RA); break; case OP_MODULE: printf("OP_MODULE\tR%d\t:%s", GETARG_A(c), mrb_sym2name(mrb, irep->syms[GETARG_B(c)])); print_lv(mrb, irep, c, RA); break; case OP_EXEC: printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1); print_lv(mrb, irep, c, RA); break; case OP_SCLASS: printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c)); print_lv(mrb, irep, c, RAB); break; case OP_TCLASS: printf("OP_TCLASS\tR%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_ERR: { mrb_value v = irep->pool[GETARG_Bx(c)]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); printf("OP_ERR\t%s\n", RSTRING_PTR(s)); } break; case OP_EPUSH: printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1); break; case OP_ONERR: printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c)); break; case OP_RESCUE: printf("OP_RESCUE\tR%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_RAISE: printf("OP_RAISE\tR%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_POPERR: printf("OP_POPERR\t%d\t\t", GETARG_A(c)); print_lv(mrb, irep, c, RA); break; case OP_EPOP: printf("OP_EPOP\t%d\n", GETARG_A(c)); break; default: printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c), GETARG_A(c), GETARG_B(c), GETARG_C(c)); break; } mrb_gc_arena_restore(mrb, ai); } printf("\n"); #endif }