Beispiel #1
0
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");
 }
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}
Beispiel #4
0
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 */
}
Beispiel #5
0
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;
}
Beispiel #6
0
/* 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;
}
Beispiel #7
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 */
}
Beispiel #8
0
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 */
}
Beispiel #9
0
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());
}
Beispiel #10
0
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);
      )
Beispiel #11
0
/* 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;
}
Beispiel #12
0
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");
 }
}
Beispiel #13
0
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;
}
Beispiel #14
0
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];
}
Beispiel #15
0
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;
      }
    }
  }
}
Beispiel #16
0
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;
    }
  }
}
Beispiel #17
0
/*
 * 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);
}
Beispiel #18
0
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);
    }
}
Beispiel #19
0
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");
 }
}
Beispiel #20
0
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];
}
Beispiel #21
0
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(&regs[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */
        memmove(&regs[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(&regs[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(&regs[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, &regs[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;
}
Beispiel #22
0
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;
    }
  }
}
Beispiel #23
0
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(&regs[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */
        memmove(&regs[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(&regs[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(&regs[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, &regs[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;
    }
Beispiel #24
0
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;
}
Beispiel #25
0
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");
    }
}
Beispiel #26
0
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(&regs[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */
        }
        if (m2) {
          memmove(&regs[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(&regs[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(&regs[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, &regs[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), &regs[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;
}
Beispiel #27
0
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];
}
Beispiel #28
0
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");
}
Beispiel #29
0
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");
 }
}
Beispiel #30
0
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
}