Example #1
0
void Compiler::CompileNewtable() {
    int a = GETARG_A(cs_.instr_);
    int b = GETARG_B(cs_.instr_);
    int c = GETARG_C(cs_.instr_);
    auto& ra = stack_.GetR(a);
    auto args = {cs_.values_.state, ra.GetTValue()};
    auto table = cs_.CreateCall("lll_newtable", args);
    if (b != 0 || c != 0) {
        args = {
            cs_.values_.state,
            table,
            cs_.MakeInt(luaO_fb2int(b)),
            cs_.MakeInt(luaO_fb2int(c))
        };
        cs_.CreateCall("luaH_resize", args);
    }
    auto& ra1 = stack_.GetR(a + 1);
    CompileCheckcg(ra1.GetTValue());
}
Example #2
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(luaV_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 (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
            dojump(L, pc, GETARG_sBx(*pc));
        )
        pc++;
        continue;
      }
Example #3
0
File: lvm.c Project: 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;
      }
Example #4
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;
      }