Пример #1
0
void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
  if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
  lua_assert(!ttisstring(p1) && !ttisnumber(p1));
  luaG_typeerror(L, p1, "concatenate");
}
Пример #2
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];
}
Пример #3
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, 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];
}
Пример #4
0
static const char *kname (Proto *p, int c) {
  if (ISK(c) && ttisstring(&p->k[INDEXK(c)]))
    return svalue(&p->k[INDEXK(c)]);
  else
    return "?";
}
Пример #5
0
l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) {
  if (ttisstring(p1) || cvt2str(p1)) p1 = p2;
  luaG_typeerror(L, p1, "concatenate");
}
Пример #6
0
void luaV_execute (lua_State *L, int nexeccalls) {
  LClosure *cl;
  StkId base;
  TValue *k;
  const Instruction *pc;
 reentry:  /* entry point */
  lua_assert(isLua(L->ci));
  pc = L->savedpc;
  cl = &clvalue(L->ci->func)->l;
  base = L->base;
  k = cl->p->k;
  /* main loop of interpreter */
  for (;;) {
    const Instruction i = *pc++;
    StkId ra;
    if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
      traceexec(L, pc);
      if (L->status == LUA_YIELD) {  /* did hook yield? */
        L->savedpc = pc - 1;
        return;
      }
      base = L->base;
    }
    /* warning!! several calls may realloc the stack and invalidate `ra' */
    ra = RA(i);
    lua_assert(base == L->base && L->base == L->ci->base);
    lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
    lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
    switch (GET_OPCODE(i)) {
      case OP_MOVE: {
        setobjs2s(L, ra, RB(i));
        continue;
      }
      case OP_LOADK: {
        setobj2s(L, ra, KBx(i));
        continue;
      }
      case OP_LOADBOOL: {
        setbvalue(ra, GETARG_B(i));
        if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */
        continue;
      }
      case OP_LOADNIL: {
        TValue *rb = RB(i);
        do {
          setnilvalue(rb--);
        } while (rb >= ra);
        continue;
      }
      case OP_GETUPVAL: {
        int b = GETARG_B(i);
        setobj2s(L, ra, cl->upvals[b]->v);
        continue;
      }
      case OP_GETGLOBAL: {
        TValue g;
        TValue *rb = KBx(i);
        sethvalue(L, &g, cl->env);
        lua_assert(ttisstring(rb));
        Protect(luaV_gettable(L, &g, rb, ra));
        continue;
      }
      case OP_GETTABLE: {
        Protect(luaV_gettable(L, RB(i), RKC(i), ra));
        continue;
      }
      case OP_SETGLOBAL: {
        TValue g;
        sethvalue(L, &g, cl->env);
        lua_assert(ttisstring(KBx(i)));
        Protect(luaV_settable(L, &g, KBx(i), ra));
        continue;
      }
      case OP_SETUPVAL: {
        UpVal *uv = cl->upvals[GETARG_B(i)];
        setobj(L, uv->v, ra);
        luaC_barrier(L, uv, ra);
        continue;
      }
      case OP_SETTABLE: {
        Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
        continue;
      }
      case OP_NEWTABLE: {
        int b = GETARG_B(i);
        int c = GETARG_C(i);
        sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
        Protect(luaC_checkGC(L));
        continue;
      }
      case OP_SELF: {
        StkId rb = RB(i);
        setobjs2s(L, ra+1, rb);
        Protect(luaV_gettable(L, rb, RKC(i), ra));
        continue;
      }
      case OP_ADD: {
        arith_op(luai_numadd, TM_ADD);
        continue;
      }
      case OP_SUB: {
        arith_op(luai_numsub, TM_SUB);
        continue;
      }
      case OP_MUL: {
        arith_op(luai_nummul, TM_MUL);
        continue;
      }
      case OP_DIV: {
        arith_op(luai_numdiv, TM_DIV);
        continue;
      }
      case OP_MOD: {
        arith_op(luai_nummod, TM_MOD);
        continue;
      }
      case OP_POW: {
        arith_op(luai_numpow, TM_POW);
        continue;
      }
      case OP_UNM: {
        TValue *rb = RB(i);
        if (ttisnumber(rb)) {
          lua_Number nb = nvalue(rb);
          setnvalue(ra, luai_numunm(nb));
        }
        else {
          Protect(Arith(L, ra, rb, rb, TM_UNM));
        }
        continue;
      }
      case OP_NOT: {
        int res = l_isfalse(RB(i));  /* next assignment may change this value */
        setbvalue(ra, res);
        continue;
      }
      case OP_LEN: {
        const TValue *rb = RB(i);
        switch (ttype(rb)) {
          case LUA_TTABLE: {
            setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
            break;
          }
          case LUA_TSTRING: {
            setnvalue(ra, cast_num(tsvalue(rb)->len));
            break;
          }
          default: {  /* try metamethod */
            Protect(
              if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
                luaG_typeerror(L, rb, "get length of");
            )
          }
        }
        continue;
      }
      case OP_CONCAT: {
        int b = GETARG_B(i);
        int c = GETARG_C(i);
        Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
        setobjs2s(L, RA(i), base+b);
        continue;
      }
      case OP_JMP: {
        dojump(L, pc, GETARG_sBx(i));
        continue;
      }
      case OP_EQ: {
        TValue *rb = RKB(i);
        TValue *rc = RKC(i);
        Protect(
          if (equalobj(L, rb, rc) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
      case OP_LT: {
        Protect(
          if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
      case OP_LE: {
        Protect(
          if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
Пример #7
0
Файл: lvm.c Проект: zapline/zlib
static void Arith (lua_State *L, StkId ra, const TValue *rb,
                   const TValue *rc, TMS op) {
  TValue tempb, tempc;
  const TValue *b, *c;
#if LUA_REFCOUNT
  luarc_newvalue(&tempb);
  luarc_newvalue(&tempc);
  if ((b = luaV_tonumber(L, rb, &tempb)) != NULL &&
      (c = luaV_tonumber(L, rc, &tempc)) != NULL) {
#else
  if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
      (c = luaV_tonumber(rc, &tempc)) != NULL) {
#endif /* LUA_REFCOUNT */
    lua_Number nb = nvalue(b), nc = nvalue(c);
#if LUA_REFCOUNT
    luarc_cleanvalue(&tempb);
    luarc_cleanvalue(&tempc);
#endif /* LUA_REFCOUNT */
    switch (op) {
      case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
      case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
      case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
      case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break;
      case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break;
      case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
      case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
      default: lua_assert(0); break;
    }
  }
#if LUA_REFCOUNT
  else if (!call_binTM(L, rb, rc, ra, op)) {
    luarc_cleanvalue(&tempb);
    luarc_cleanvalue(&tempc);
    luaG_aritherror(L, rb, rc);
  }
#else
  else if (!call_binTM(L, rb, rc, ra, op))
    luaG_aritherror(L, rb, rc);
#endif /* LUA_REFCOUNT */
}



/*
** some macros for common tasks in `luaV_execute'
*/

#define runtime_check(L, c)	{ if (!(c)) break; }

#define RA(i)	(base+GETARG_A(i))
/* to be used after possible stack reallocation */
#define RB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
#define RC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
#define RKB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
	ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
#define RKC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
	ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
#define KBx(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i))


#define dojump(L,pc,i)	{(pc) += (i); luai_threadyield(L);}


#define Protect(x)	{ L->savedpc = pc; {x;}; base = L->base; }


#define arith_op(op,tm) { \
        TValue *rb = RKB(i); \
        TValue *rc = RKC(i); \
        if (ttisnumber(rb) && ttisnumber(rc)) { \
          lua_Number nb = nvalue(rb), nc = nvalue(rc); \
          setnvalue(ra, op(nb, nc)); \
        } \
        else \
          Protect(Arith(L, ra, rb, rc, tm)); \
      }

#if LUA_BITFIELD_OPS

#define bit_op(op) { \
        TValue *rb = RKB(i); \
        TValue *rc = RKC(i); \
        if (ttisnumber(rb) && ttisnumber(rc)) { \
          unsigned int nb = (unsigned int)nvalue(rb), nc = (unsigned int)nvalue(rc); \
          setnvalue(ra, nb op nc); \
        } \
        else \
          luaG_aritherror(L, rb, rc); \
      }

#endif /* LUA_BITFIELD_OPS */



void luaV_execute (lua_State *L, int nexeccalls) {
  LClosure *cl;
  StkId base;
  TValue *k;
  const Instruction *pc;
 reentry:  /* entry point */
  lua_assert(isLua(L->ci));
  pc = L->savedpc;
  cl = &clvalue(L->ci->func)->l;
  base = L->base;
  k = cl->p->k;
  /* main loop of interpreter */
  for (;;) {
    const Instruction i = *pc++;
    StkId ra;
    if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
      traceexec(L, pc);
      if (L->status == LUA_YIELD) {  /* did hook yield? */
        L->savedpc = pc - 1;
        return;
      }
      base = L->base;
    }
    /* warning!! several calls may realloc the stack and invalidate `ra' */
    ra = RA(i);
    lua_assert(base == L->base && L->base == L->ci->base);
    lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
    lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
    switch (GET_OPCODE(i)) {
      case OP_MOVE: {
        setobjs2s(L, ra, RB(i));
        continue;
      }
      case OP_LOADK: {
        setobj2s(L, ra, KBx(i));
        continue;
      }
      case OP_LOADBOOL: {
        setbvalue(ra, GETARG_B(i));
        if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */
        continue;
      }
      case OP_LOADNIL: {
        TValue *rb = RB(i);
        do {
          setnilvalue(rb--);
        } while (rb >= ra);
        continue;
      }
      case OP_GETUPVAL: {
        int b = GETARG_B(i);
        setobj2s(L, ra, cl->upvals[b]->v);
        continue;
      }
      case OP_GETGLOBAL: {
        TValue g;
        TValue *rb = KBx(i);
#if LUA_REFCOUNT
        sethvalue2n(L, &g, cl->env);
#else
        sethvalue(L, &g, cl->env);
#endif /* LUA_REFCOUNT */
        lua_assert(ttisstring(rb));
        Protect(luaV_gettable(L, &g, rb, ra));
#if LUA_REFCOUNT
		setnilvalue(&g);
#endif /* LUA_REFCOUNT */
        continue;
      }
      case OP_GETTABLE: {
        Protect(luaV_gettable(L, RB(i), RKC(i), ra));
        continue;
      }
      case OP_SETGLOBAL: {
        TValue g;
#if LUA_REFCOUNT
        sethvalue2n(L, &g, cl->env);
#else
        sethvalue(L, &g, cl->env);
#endif /* LUA_REFCOUNT */
        lua_assert(ttisstring(KBx(i)));
        Protect(luaV_settable(L, &g, KBx(i), ra));
#if LUA_REFCOUNT
		setnilvalue(&g);
#endif /* LUA_REFCOUNT */
        continue;
      }
      case OP_SETUPVAL: {
        UpVal *uv = cl->upvals[GETARG_B(i)];
        setobj(L, uv->v, ra);
        luaC_barrier(L, uv, ra);
        continue;
      }
      case OP_SETTABLE: {
        Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
        continue;
      }
      case OP_NEWTABLE: {
        int b = GETARG_B(i);
        int c = GETARG_C(i);
        sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
        Protect(luaC_checkGC(L));
        continue;
      }
      case OP_SELF: {
        StkId rb = RB(i);
        setobjs2s(L, ra+1, rb);
        Protect(luaV_gettable(L, rb, RKC(i), ra));
        continue;
      }
      case OP_ADD: {
        arith_op(luai_numadd, TM_ADD);
        continue;
      }
      case OP_SUB: {
        arith_op(luai_numsub, TM_SUB);
        continue;
      }
      case OP_MUL: {
        arith_op(luai_nummul, TM_MUL);
        continue;
      }
      case OP_DIV: {
        arith_op(luai_numdiv, TM_DIV);
        continue;
      }
      case OP_MOD: {
        arith_op(luai_nummod, TM_MOD);
        continue;
      }
      case OP_POW: {
        arith_op(luai_numpow, TM_POW);
        continue;
      }
      case OP_UNM: {
        TValue *rb = RB(i);
        if (ttisnumber(rb)) {
          lua_Number nb = nvalue(rb);
          setnvalue(ra, luai_numunm(nb));
        }
        else {
          Protect(Arith(L, ra, rb, rb, TM_UNM));
        }
        continue;
      }
      case OP_NOT: {
        int res = l_isfalse(RB(i));  /* next assignment may change this value */
        setbvalue(ra, res);
        continue;
      }
#if LUA_BITFIELD_OPS
      case OP_BAND: {
        bit_op(&);
        continue;
      }
      case OP_BOR: {
        bit_op(|);
        continue;
      }
      case OP_BXOR: {
        bit_op(^);
        continue;
      }
      case OP_BSHL: {
        bit_op(<<);
        continue;
      }
      case OP_BSHR: {
        bit_op(>>);
        continue;
      }
#endif /* LUA_BITFIELD_OPS */
      case OP_LEN: {
        const TValue *rb = RB(i);
        switch (ttype(rb)) {
          case LUA_TTABLE: {
            setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
            break;
          }
          case LUA_TSTRING: {
            setnvalue(ra, cast_num(tsvalue(rb)->len));
            break;
          }
#if LUA_WIDESTRING
          case LUA_TWSTRING: {
            setnvalue(ra, cast_num(tsvalue(rb)->len));
            break;
          }
#endif /* LUA_WIDESTRING */
          default: {  /* try metamethod */
            Protect(
              if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
                luaG_typeerror(L, rb, "get length of");
            )
          }
        }
        continue;
      }
      case OP_CONCAT: {
        int b = GETARG_B(i);
        int c = GETARG_C(i);
        Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
        setobjs2s(L, RA(i), base+b);
        continue;
      }
      case OP_JMP: {
        dojump(L, pc, GETARG_sBx(i));
        continue;
      }
      case OP_EQ: {
        TValue *rb = RKB(i);
        TValue *rc = RKC(i);
        Protect(
          if (equalobj(L, rb, rc) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
      case OP_LT: {
        Protect(
          if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
      case OP_LE: {
        Protect(
          if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
Пример #8
0
static int valismarked (const TObject *o) {
  if (ttisstring(o) || ttiswstring(o))
    stringmark(tsvalue(o));  /* strings are `values', so are never weak */
  return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0);
}
Пример #9
0
LUA_API int lua_isstring (lua_State *L, int idx) {
  const TValue *o = index2addr(L, idx);
  return (ttisstring(o) || cvt2str(o));
}
Пример #10
0
// 已经准备好了lua函数的调用环境,开始逐句执行lua函数的指令
void luaV_execute (lua_State *L, int nexeccalls) {
  LClosure *cl;
  StkId base;
  TValue *k;
  const Instruction *pc;
 reentry:  /* entry point */
  pc = L->savedpc;					//这时候已经保存了lua函数的第一个指令位置
  cl = &clvalue(L->ci->func)->l;
  base = L->base;
  k = cl->p->k;
  /* main loop of interpreter */
  for (;;) {
    const Instruction i = *pc++;
    StkId ra;
    if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
      traceexec(L, pc);
      if (L->status == LUA_YIELD) {  /* did hook yield? */
        L->savedpc = pc - 1;
        return;
      }
      base = L->base;
    }
    /* warning!! several calls may realloc the stack and invalidate `ra' */
    ra = RA(i);
    lua_assert(base == L->base && L->base == L->ci->base);
    lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
    lua_assert(L->top == L->ci->top || luaG_checkopenop(i));

	// 阅读说明:
	// 每lua的一个函数在编译器会生成这个函数的信息:函数引用到的upvalue,函数固定参数
	// 数量,是否含有可变参数,指令序列等等,这些都记录在Proto结构体中。
	// 可以通过 luac -o tmp <luafile> | luac -l tmp 来函数对应的字节码以及Proto信息
	// 例如以下lua代码:
	// -- t.lua
	// local x, y, z
	// x = x*y + y*z + x*z - (x*x + y*y + z*z)
	// 得到以下输出:
	// main <t.lua:0,0> (12 instructions, 48 bytes at 0074B6A0)
	// 0 + params, 6 slots, 0 upvalues, 3 locals, 0 constants, 0 functions
	//	1[2]	MUL      	3 0 1
	//	2[2]	MUL      	4 1 2
	//	3[2]	ADD      	3 3 4
	//	4[2]	MUL      	4 0 2
	//	5[2]	ADD      	3 3 4
	//	6[2]	MUL      	4 0 0
	//	7[2]	MUL      	5 1 1
	//	8[2]	ADD      	4 4 5
	//	9[2]	MUL      	5 2 2
	//	10[2]	ADD      	4 4 5
	//	11[2]	SUB      	0 3 4
	//	12[2]	RETURN   	0 1
	// 从输出可以得到的信息包括:
	//  1 生成了多少个Proto
	//  2 Proto对应的lua源代码在哪里 (<t.lua:0,0>)
	//  3 Proto中的sizecode (12 instructions, 48 bytes at 0074B6A0)
	//  4 Proto中的固定参数数量numparams (0 + params,这里的0)
	//  5 Proto是否有可变参数is_vararg (0 + params,这里的+表示带有可变参数,没有可变参数就是 0 params)
	//  6 Proto中在栈上用到的临时变量总数maxstacksize (6 slots,表示local变量+计算中辅助用的临时变量=6个)
	//  7 Proto中用到的upvalue数量nups (0 upvalues,表示用到了0个upvalue)
	//  8 Proto中用到的local变量数量sizelocvars (3 locals,刚好t.lua用到了x,y,z三个local变量)
	//  9 Proto中用到的字面常量数量sizek (0 constants)
	// 10 Proto中用到的Closure数量sizep (0 functions)
	// 11 Proto中生成的字节码指令内容code,每条指令包括:
	//    a 指令下标
	//    b 指令在源代码中对应的行号
	//    c 指令opcode
	//    d 指令参数
	// 
	// PS:第6条和第8条,由于计算一条表达式需要用到的辅助临时变量数目是不定的,但是是可以通过
	// 分析一条表达式的AST来确定最少需要几个临时变量(后续遍历+逆波兰式拟真)。
	// PS:lua是会对表达式进行常量计算优化的!例如 x = x + 5*60*60*1000,只有一个常量18000000
	// PS:函数执行的时候需要用到“一段”参数栈上的空间,也就是第6条所谓的临时变量。这一段空间的
	// 范围由L->base开始,到L->top结束。通过相对L->base的下标来标识具体的变量是哪个。一般来说,
	// 固定参数的函数,L->base指向第一个固定参数,而L->base-1指向当前正在运行的函数;而可变参数
	// 的函数,L->base和当前正在运行的函数中间,保存有全部的传入参数。
    switch (GET_OPCODE(i)) {

	  // 功能:用一个已有的变量创建一个新的变量
	  // 将一个 lua_TValue设置成另一个lua_TValue的样子
      // iABC: A待创建变量在参数栈索引,B参数栈已有lua变量的索引。
      case OP_MOVE: {		
		// local x, y   -----> 记录 index(x) = 0, index(y) = 1
		// x = ...
		// .....
		// y = x    -----> OP_MOVE: 1, 0
        setobjs2s(L, ra, RB(i));
        continue;
      }

	  // 功能:用一个常量来创建一个新的变量
	  // 从常量池(保存在Proto类型中)中保存的常量赋值给栈上的变量
	  // iABx: A待创建变量在参数栈索引,Bx常量在常量池的索引
      case OP_LOADK: {		
		// local x = 9	-----> 记录 index(x) = 0, index(constval(9)) = 1 
		//              >----> OP_LOADK: 0, 1
        setobj2s(L, ra, KBx(i));
        continue;
      }

	  // 功能:用一个布尔值来创建一个新的变量
	  // iABC: A待创建变量在参数栈索引,B布尔值,C通常是0
      case OP_LOADBOOL: {	
		// 注意,local c = true这种,true就不作为一个常量放到k里面
		// 而是作为字面值放到参数B里面了!所以不需要KB(i)!
		// local a = false -----> 记录 index(a) = 0
		//                 >----> OP_LOADBOOL 0 0 0
		// local b = true  -----> 记录 index(b) = 1
		//                 >----> OP_LOADBOOL 1 1 0
        setbvalue(ra, GETARG_B(i));
        if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */
        continue;
      }

	  // 功能:用nil来初始化一个到多个变量
	  // 类似于bzero,这个指令会把一段内存中的变量置为nil
	  // iABC: A第一个要置nil的变量参数栈索引,B最后一个要置nil的变量参数栈索引
      case OP_LOADNIL: {
		// local a, b, c, d, e, f, g = 1, 2, 3, 4 -----> index(a~g) = 0~6
		//                                        >----> OP_LOADNIL 4 6
        TValue *rb = RB(i);
        do {
          setnilvalue(rb--);
        } while (rb >= ra);
        continue;
      }

	  // 功能:用upvalue来创建一个新的变量
	  // 所谓的“创建”操作,其实创建的不是副本而是引用
	  // iABC: A待创建变量在参数栈索引,B当前函数的upvalue表的索引
      case OP_GETUPVAL: {	
		// local x = {}
		// ...  -- do something to x
		// function f() local a = x[1] end   -----> 记录index(a) = 0, index(upval(x)) = 1
		//                                   >----> OP_GETUPVAL 0 1
        int b = GETARG_B(i);
        setobj2s(L, ra, cl->upvals[b]->v);
        continue;
      }

	  // 功能:从全局表中取某个key的值来创建一个新的变量
	  // iABx:A待创建变量在参数栈索引,Bxkey对应的常量在常量池的索引
      case OP_GETGLOBAL: {
		// local a = dofile    ------> 记录 index(a) = 0, index(constval("dofile")) = 1
		//                     >-----> OP_GETGLOBAL 0 1
        TValue g;
        TValue *rb = KBx(i);
        sethvalue(L, &g, cl->env);
        lua_assert(ttisstring(rb));
        Protect(luaV_gettable(L, &g, rb, ra));
        continue;
      }

	  // 功能:从某个table中取某个key的值来创建一个新的变量
	  // iABC:A待创建变量在参数栈索引,B要取出key的table变量在参数栈的索引,Ckey对应的参数栈下标或者常量池下标
      case OP_GETTABLE: {
		// local a = hello["world"] -----> 记录 index(a) = 0, index(hello) = 1 index(constval("world")) = 0
		//                          >----> OP_GETTABLE 0 1 0|BITRK
        Protect(luaV_gettable(L, RB(i), RKC(i), ra));
        continue;
      }

	  // 功能:将参数栈上变量设置到全局表中
	  // iABx:A要写入全局表的变量在栈上的索引,Bx写入到全局表的key在常量池中的下标
      case OP_SETGLOBAL: {
		// 假设我要替换 bit库
		// local mybit = {}
		// mybit.band = ...
		// mybit.bor = ...
		// mybit.bxor = ...
		// ...
		// bit = mybit -----> 记录 index(mybit) = 0, index(constval("bit")) = 1
		//             >----> OP_SETGLOBAL 0 1
        TValue g;
        sethvalue(L, &g, cl->env);
        lua_assert(ttisstring(KBx(i)));
        Protect(luaV_settable(L, &g, KBx(i), ra));
        continue;
      }

	  // 功能:修改upvalue的值
	  // iABC:A要写入upvalue的变量在参数栈上的索引,B待写入的upvalue在upvalue表的索引
      case OP_SETUPVAL: {
		// local a = 5
		// function p()
		//  a = "hello" -----> 记录 index(upval(a)) = 0, index(constval("hello")) = 1
		//              >----> OP_SETUPVAL 0 1
		// end
        UpVal *uv = cl->upvals[GETARG_B(i)];
        setobj(L, uv->v, ra);
        luaC_barrier(L, uv, ra);
        continue;
      }

	  // 功能:修改某个table对应的key
	  // iABC:A要写入table变量在参数栈的索引,B要写入的key的变量的栈索引或者常量索引,C要写入的value的变量索引或者常量索引
      case OP_SETTABLE: {
		// local a = {}
		// a[5] = 3
        Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
        continue;
      }

	  // 功能:在栈上创建一个table变量
	  // iABC:A存放table变量的参数栈索引,B创建的table变量的数组容量,C创建的table变量的字典容量
      case OP_NEWTABLE: {
		// local a = {}   -----> index(a) = 0
		//                >----> OP_NEWTABLE 0 szArray szHash
        int b = GETARG_B(i);
        int c = GETARG_C(i);
        sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
        Protect(luaC_checkGC(L));			// 注意,创建table可能会引起GC
        continue;
      }

	  // 功能:把self.method和self放到参数栈上相邻的两个位置。
	  // 为成员方法调用的语法糖提供支持
	  // iABC:A存放self.method的参数栈索引,B存放self的参数栈索引,C需要从self中调用的方法对应的变量索引或者常量索引
	  // 执行完成后,栈上内容为: ... -> self.method -> self -> ...
	  //                                   ^
	  //                                   RA
	  // 当然,OP_SELF之后能看到OP_CALL的身影
      case OP_SELF: {
		// CCNode:create()  -> index(constants("CCNode")) = 1, index(constants("create")) = 2
		//                  -> OP_GETGLOBAL 0 1
		//                  -> OP_SELF 0 0 2
		//                  -> OP_CALL 0 2 1
        StkId rb = RB(i);
        setobjs2s(L, ra+1, rb);
        Protect(luaV_gettable(L, rb, RKC(i), ra));
        continue;
      }

	//---------------------------------------------------------------------------运算符指令
	  // 功能:实现二元运算符:+, -, *, /, %, ^
	  // iABC:A存放运算结果的参数栈索引,B存放第一操作数的参数栈索引,C存放第二操作数的参数栈索引
      case OP_ADD: {
		// local a, b, c = ... -----> index(a) = 0, index(b) = 1, index(c) = 2
		// a = b + c -----> OP_ADD 0 1|BITRK 2|BITRK
		// a = 1 + b -----> index(constval(1)) = 0
		//           >----> OP_ADD 0 0 1|BITRK
		// a = 1 + 100 -----> index(constval(1)) = 0, index(constval(100)) = 1
		//             >----> OP_ADD 0 0 1
        arith_op(luai_numadd, TM_ADD);
        continue;
      }
      case OP_SUB: {
		// see OP_ADD
        arith_op(luai_numsub, TM_SUB);
        continue;
      }
      case OP_MUL: {
		// see OP_ADD
        arith_op(luai_nummul, TM_MUL);
        continue;
      }
      case OP_DIV: {
		// see OP_ADD
        arith_op(luai_numdiv, TM_DIV);
        continue;
      }
      case OP_MOD: {
		// 这个很特殊!由于lua没有整数,所以mod可不是%这个运算符!
		// 这里定义 mod(x, y) => (x - floor(x/y)*y)
		// see OP_ADD
        arith_op(luai_nummod, TM_MOD);
        continue;
      }
      case OP_POW: {
		// see OP_ADD
        arith_op(luai_numpow, TM_POW);
        continue;
      }

	  // 功能:实现一元运算符 -, not, #
	  // iABC:A存放运算结果的参数栈索引,B存放操作数的参数栈索引
      case OP_UNM: {
		// local a = -b -----> index(a) = 1, index(b) = 2
		//              >----> OP_UNM 1 2
        TValue *rb = RB(i);
        if (ttisnumber(rb)) {
          lua_Number nb = nvalue(rb);
          setnvalue(ra, luai_numunm(nb));
        }
        else {
          Protect(Arith(L, ra, rb, rb, TM_UNM));
        }
        continue;
      }
      case OP_NOT: {
		// local a = not b -----> index(a) = 1, index(b) = 2
		//                 >----> OP_NOT 1 2
		// 那local a = not true呢?人家编译期就给你处理好了
        int res = l_isfalse(RB(i));  /* next assignment may change this value */
        setbvalue(ra, res);
        continue;
      }
      case OP_LEN: {
		// local a = #b -----> index(a) = 1, index(b) = 2
		//              >----> OP_LEN 1 2
        const TValue *rb = RB(i);
        switch (ttype(rb)) {
          case LUA_TTABLE: {
            setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
            break;
          }
          case LUA_TSTRING: {
            setnvalue(ra, cast_num(tsvalue(rb)->len));
            break;
          }
          default: {  /* try metamethod */
            Protect(
              if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
                luaG_typeerror(L, rb, "get length of");
            )
          }
        }
        continue;
      }

	  // 功能:实现字符串拼接运算符 ..
	  // iABC:A拼接后存放结果的参数栈索引,B第一个要拼接的变量的参数栈索引,C最后一个要拼接的变量的参数栈索引
	  // 要执行这个指令,对参数栈有特殊要求:
	  // ... -> string1 -> string2 ... -> stringN -> ...
	  //          ^                          ^
	  //          RB                         RC
      case OP_CONCAT: {
		// 类似OP_LOADNIL,只不过,这次范围是[rb,rc],loadnil是[ra,rb]
		// local b, c, d, a = "hello", "world", "!"
		// a = b .. c .. d -----> index(a) = 4, index(b~d) = 1~3
		//                 >----> OP_CONCAT 4 1 3
		// 问题是如果b~d不能保证是连续的怎么办?答案是一个个MOVE上去在OP_CONCAT...
        int b = GETARG_B(i);
        int c = GETARG_C(i);
        Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
        setobjs2s(L, RA(i), base+b);
        continue;
      }

	//---------------------------------------------------------------------------跳转指令
	  // 功能:无条件跳转
	  // iAsBx:A不使用,sBx跳转偏移
	  // 一般这个语句不单独出现,都是在一些条件控制中和其他的条件跳转指令配合使用的。
      case OP_JMP: {
		// 无条件跳转指令。由于跳转偏移总是有正向和反向之分的,所以需要用到
		// 负数。那就只能用iAsBx类型的指令了。而sBx是有长度限制的!
		// 所以,如果生成的指令很多,超过了sBx的长度限制,可能就会编译失败
        dojump(L, pc, GETARG_sBx(i));
        continue;
      }

	  // 功能:检查两个变量是否相等,满足预期则跳转。配合OP_JMP使用。
	  // iABC:A纯数字,对比较结果的预期,满足预期则跳转,B参数1的索引,C参数2的索引
      case OP_EQ: {
		// if a == b then -----> index(a) = 1, index(b) = 2
		//                >----> 这里将生成两行指令:
		//                >----> OP_EQ  0 1 2	// 用0,因为成立的话跳过,不成立才执行
		//                >----> OP_JMP N		// N 表示then ... end中间的指令数量
		//                >----> ...			// Instructions between "then" and "end"
        TValue *rb = RKB(i);
        TValue *rc = RKC(i);
        Protect(
          if (equalobj(L, rb, rc) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
	
	  // 功能:检查两个变量是否小于,满足预期则跳转。配合OP_JMP使用。
	  // iABC:A纯数字,对比较结果的预期,满足预期则跳转,B参数1的索引,C参数2的索引
      case OP_LT: {
		// if a < b then -----> index(a) = 1, index(b) = 2
		//               >----> 这里将生成两行指令:
		//               >----> OP_LT  0 1 2	// 用0,因为成立的话跳过,不成立才执行
		//               >----> OP_JMP N		// N 表示then ... end中间的指令数量
		//               >----> ...				// Instructions between "then" and "end"
        Protect(
          if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }

	  // 功能:检查两个变量是否小于等于,满足预期则跳转。配合OP_JMP使用。
	  // iABC:A纯数字,对比较结果的预期,满足预期则跳转,B参数1的索引,C参数2的索引
      case OP_LE: {
		  // if a <= b then -----> index(a) = 1, index(b) = 2
		  //                >----> 这里将生成两行指令:
		  //                >----> OP_LE  0 1 2	// 用0,因为成立的话跳过,不成立才执行
		  //                >----> OP_JMP N		// N 表示then ... end中间的指令数量
		  //                >----> ...			// Instructions between "then" and "end"
		  Protect(
          if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
Пример #11
0
StkId luaV_execute (lua_State *L) {
  LClosure *cl;
  TObject *k;
  const Instruction *pc;
 callentry:  /* entry point when calling new functions */
  if (L->hookmask & LUA_MASKCALL)
    luaD_callhook(L, LUA_HOOKCALL, -1);
 retentry:  /* entry point when returning to old functions */
  L->ci->u.l.pc = &pc;
  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(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;
      }
    }
  }
}
Пример #12
0
Файл: block.c Проект: erik/bijou
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);
    }
}
Пример #13
0
/* histogram: key should be number or string, value must be number */
void kp_table_histogram(ktap_State *ks, Table *t)
{
	struct table_hist_record *thr;
	char dist_str[40];
	int i, ratio, total = 0, count = 0;

	thr = kp_malloc(ks, sizeof(*thr) * (t->sizearray + sizenode(t)));

	for (i = 0; i < t->sizearray; i++) {
		Tvalue *v = &t->array[i];

		if (isnil(v))
			continue;

		if (!ttisnumber(v))
			goto error;

		setnvalue(&thr[count++].key, i + 1);
		total += nvalue(v);
	}

	for (i = 0; i < sizenode(t); i++) {
		Node *n = &t->node[i];
		int num;

		if (isnil(gkey(n)))
			continue;

		if (!ttisnumber(gval(n)))
			goto error;

		num = nvalue(gval(n));
		setobj(ks, &thr[count].key, gkey(n));
		setobj(ks, &thr[count].val, gval(n));
		count++;
		total += nvalue(gval(n));
	}

	sort(thr, count, sizeof(struct table_hist_record), hist_record_cmp, NULL);

	kp_printf(ks, "%32s%s%s\n", "value ", DISTRIBUTION_STR, " count");
	dist_str[sizeof(dist_str) - 1] = '\0';
	for (i = 0; i < count; i++) {
		Tvalue *key = &thr[i].key;
		Tvalue *val = &thr[i].val;

		memset(dist_str, ' ', sizeof(dist_str) - 1);
		ratio = (nvalue(val) * (sizeof(dist_str) - 1)) / total;
		memset(dist_str, '@', ratio);

		if (ttisstring(key)) {
			char buf[32 + 1] = {0};
			char *keystr;

			if (strlen(svalue(key)) > 32) {
				strncpy(buf, svalue(key), 32-4);
				memset(buf + 32-4, '.', 3);
				keystr = buf;
			} else
				keystr = svalue(key);

			kp_printf(ks, "%32s |%s%-10d\n", keystr, dist_str,
					nvalue(val));
		} else
			kp_printf(ks, "%32d | %s%-10d\n", nvalue(key),
					dist_str, nvalue(val));
	}

	goto out;

 error:
	kp_printf(ks, "error: table histogram only handle "
			" (key: string/number val: number)\n");
 out:
	kp_free(ks, thr);
}
Пример #14
0
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
  int loop;
  for (loop = 0; loop < MAXTAGLOOP; loop++) {
    const TValue *tm = 0; /* LUA-VEC -- compiler gives a warning of uninitialized value on this so we set it to 0 */
    if (ttistable(t)) {  /* `t' is a table? */
      Table *h = hvalue(t);
      const TValue *res = luaH_get(h, key); /* do a primitive get */
      if (!ttisnil(res) ||  /* result is no nil? */
          (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
        setobj2s(L, val, res);
        return;
      }
      /* else will try the tag method */
    }
    else if (ttisvec(t)) { /* LUA-VEC -- vec[idx] operator */
      /* issue: "index" may not be the correct arg for luaG_typeerror in here */
      if (ttisnumber(key) &&   /* acessing vec by a number? */
          (nvalue(key) >= 1 && nvalue(key) <= 4)) {  /* index is between 1-4? */
        TValue res;
        setnvalue(&res, vecvalue(t)[(int)nvalue(key)-1]);
        setobj2s(L, val, &res);
        return;
      }
      else if (ttisstring(key)) {  /* acessing vec by a string? */
        if (tsvalue(key)->len == 1) {
          /* accessing by a single component, such as vec.x */
          TValue res;
          switch (*getstr(tsvalue(key))) {
            case 'x':  setnvalue(&res, vecvalue(t)[0]); break;
            case 'y':  setnvalue(&res, vecvalue(t)[1]); break;
            case 'z':  setnvalue(&res, vecvalue(t)[2]); break;
            case 'w':  setnvalue(&res, vecvalue(t)[3]); break;
            default:   luaG_typeerror(L, t, "index");
          }
          setobj2s(L, val, &res);
          return;
        }
        else if (tsvalue(key)->len <= 4) {
          /* accessing by swizzling, such as vec.xy, vec.xxyz etc. */
          TValue res;
          float v[4] = {0.0f,0.0f,0.0f,0.0f};
          int i;
          for (i = 0; i < (int)tsvalue(key)->len; ++i) {
            switch (getstr(tsvalue(key))[i]) {
              case 'x':  v[i] = vecvalue(t)[0]; break;
              case 'y':  v[i] = vecvalue(t)[1]; break;
              case 'z':  v[i] = vecvalue(t)[2]; break;
              case 'w':  v[i] = vecvalue(t)[3]; break;
              default:   luaG_typeerror(L, t, "index");
            }
          }
          setvecvalue(&res, v[0], v[1], v[2], v[3]);
          setobj2s(L, val, &res);
          return;
        }
      }
      luaG_typeerror(L, t, "index");
    }
    else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
      luaG_typeerror(L, t, "index");
    if (ttisfunction(tm)) {
      callTMres(L, val, tm, t, key);
      return;
    }
    t = tm;  /* else repeat with `tm' */ 
  }
  luaG_runerror(L, "loop in gettable");
}
Пример #15
0
l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) {
    if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
    lua_assert(!ttisstring(p1) && !ttisnumber(p1));
    luaG_typeerror(L, p1, "concatenate");
}