【Lua 5.3源码】虚拟机指令分析(三) 赋值指令



1. 赋值指令

Lua中的赋值指令有如下几个:

  • OP_MOVE A B R(A) := R(B)
  • OP_LOADK A Bx R(A) := Kst(Bx)
  • OP_LOADKX A R(A) := Kst(extra arg)
  • OP_LOADBOOL A B C R(A) := (Bool)B; if (C) pc++
  • OP_LOADNIL A B R(A), R(A+1), …, R(A+B) := nil
  • OP_GETUPVAL A B R(A) := UpValue[B]
  • OP_GETTABUP A B C R(A) := UpValue[B][RK(C)]
  • OP_GETTABLE A B C R(A) := R(B)[RK(C)]
  • OP_SETTABUP A B C UpValue[A][RK(B)] := RK(C)
  • OP_SETUPVAL A B UpValue[B] := R(A)
  • OP_SETTABLE A B C R(A)[RK(B)] := RK(C)

下面会选择其中几个指令进行分析:



2. OP_MOVE:

vmcase(OP_MOVE) {
   
  setobjs2s(L, ra, RB(i));
  vmbreak;
}

首先看RBcheck_expGET_OPCODEGETARG_B

#define RB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
#define check_exp(c,e)		(lua_assert(c), (e))
#define getBMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
#define GETARG_B(i)	getarg(i, POS_B, SIZE_B)

可见check_exp宏其实是用来断言检测的,getBMode是用来获取指令的B参数格式,配合check_exp来进行判断指令格式是否合法。
最重要的是base+GETARG_B(i):

  • base记录的是栈基址,也就是函数栈的起始位置,在这里表示寄存器的起始地址。
  • GETARG_B(i),对于OP_MOVE指令来说,B参数表示一个寄存器的索引,而GETARG_B(i)就是获取这个索引值
  • base+GETARG_B(i),获取到B参数对应寄存器的值。

然后再看setobjs2s相关的代码

#define setobjs2s	setobj
#define setobj(L,obj1,obj2) \
	{ TValue *io1=(obj1); *io1 = *(obj2); \
	  (void)L; checkliveness(L,io1); }

可以看出setobjs2s(L, ra, RB(i)),就是将RB(i)寄存器的值赋值给ra,那么ra又是什么呢?其实在vmfetch中进行了初始化:

/* fetch an instruction and prepare its execution */
#define vmfetch()	{ \
  i = *(ci->u.l.savedpc++); \
  if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
    Protect(luaG_traceexec(L)); \
  ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
  lua_assert(base == ci->u.l.base); \
  lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
}

可以看到,ra就是RA(i)寄存器中的值(和RB同理)。

那么OP_MOVE指令就是将B寄存器的值赋值给A寄存器。我们可以看下如下代码编译后的字节码:

local a = 1
local b = a
main <mylua.lua:0,0> (3 instructions at 0083A2B0)
0+ params, 2 slots, 1 upvalue, 2 locals, 1 constant, 0 functions
	1	[1]	LOADK    	0 -1	; 1
	2	[2]	MOVE     	1 0
	3	[2]	RETURN   	0 1
constants (1) for 0083A2B0:
	1	1
locals (2) for 0083A2B0:
	0	a	2	4
	1	b	3	4
upvalues (1) for 0083A2B0:
	0	_ENV	1	0

可以看到,局部变量a存放在0号寄存器上,b存放在1号寄存器上,PC[1]指令表示将0号寄存器的值赋值给1号寄存器;也就是 b = a。



3. OP_LOADK:

vmcase(OP_LOADK) {
   
  TValue *rb = k + GETARG_Bx(i);
  setobj2s(L, ra, rb);
  vmbreak
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值