【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
(接上篇)
> EQOP
case EQOP:
{
Object *l = top-2;
Object *r = top-1;
--top;
if (tag(l) != tag(r))
tag(top-1) = T_NIL;
else
{
switch (tag(l))
{
case T_NIL: tag(top-1) = T_NUMBER; break;
case T_NUMBER: tag(top-1) = (nvalue(l) == nvalue(r)) ? T_NUMBER : T_NIL; break;
case T_ARRAY: tag(top-1) = (avalue(l) == avalue(r)) ? T_NUMBER : T_NIL; break;
case T_FUNCTION: tag(top-1) = (bvalue(l) == bvalue(r)) ? T_NUMBER : T_NIL; break;
case T_CFUNCTION: tag(top-1) = (fvalue(l) == fvalue(r)) ? T_NUMBER : T_NIL; break;
case T_USERDATA: tag(top-1) = (uvalue(l) == uvalue(r)) ? T_NUMBER : T_NIL; break;
case T_STRING: tag(top-1) = (strcmp (svalue(l), svalue(r)) == 0) ? T_NUMBER : T_NIL; break;
case T_MARK: return 1;
}
}
nvalue(top-1) = 1;
}
break;
判断栈顶的两个 Object 是否相等。
先判断是否是相同类型,如果不是,则不等。
否则,判断值是否相等。数值和字符串类型是判断是否值相等,而数组、函数这种则是判断其指针是否相等。
如果相等,把栈顶 Object 设置为 T_NUMBER 类型,值设置为 1。
如果不等,设置栈顶 Object 为 T_NIL(空类型足以识别它自己,此时可以认为设置什么值都无意义)。
> LTOP
case LTOP:
{
Object *l = top-2;
Object *r = top-1;
--top;
if (tag(l) == T_NUMBER && tag(r) == T_NUMBER)
tag(top-1) = (nvalue(l) < nvalue(r)) ? T_NUMBER : T_NIL;
else
{
if (tostring(l) || tostring(r))
return 1;
tag(top-1) = (strcmp (svalue(l), svalue(r)) < 0) ? T_NUMBER : T_NIL;
}
nvalue(top-1) = 1;
}
break;
判断 top-2 是否小于 top-1。只在两个 Object 均为数值型,或者可转化为字符串型时有意义。
如果判断结果为真,设置栈顶元素类型为 T_NUMBER,值为 1。
如果判断结果为假,设置栈顶元素类型为 T_NIL。
> LEOP
case LEOP:
{
Object *l = top-2;
Object *r = top-1;
--top;
if (tag(l) == T_NUMBER && tag(r) == T_NUMBER)
tag(top-1) = (nvalue(l) <= nvalue(r)) ? T_NUMBER : T_NIL;
else
{
if (tostring(l) || tostring(r))
return 1;
tag(top-1) = (strcmp (svalue(l), svalue(r)) <= 0) ? T_NUMBER : T_NIL;
}
nvalue(top-1) = 1;
}
break;
判断 top-2 是否小于等于 top-1。只在两个 Object 均为数值型,或者可转化为字符串型时有意义。
如果判断结果为真,设置栈顶元素类型为 T_NUMBER,值为 1。
如果判断结果为假,设置栈顶元素类型为 T_NIL。
> ADDOP
case ADDOP:
{
Object *l = top-2;
Object *r = top-1;
if (tonumber(r) || tonumber(l))
return 1;
nvalue(l) += nvalue(r);
--top;
}
break;
栈顶两元素 top-2 和 top-1 相加,top-1 出栈,结果保存在新的栈顶。
只在两个 Object 均可转化为数值型时该运算有效。
> SUBOP,
case SUBOP:
{
Object *l = top-2;
Object *r = top-1;
if (tonumber(r) || tonumber(l))
return 1;
nvalue(l) -= nvalue(r);
--top;
}
break;
栈顶两元素 top-2 和 top-1 相减,top-1 出栈,结果保存在新的栈顶。
只在两个 Object 均可转化为数值型时该运算有效。
> MULTOP,
case MULTOP:
{
Object *l = top-2;
Object *r = top-1;
if (tonumber(r) || tonumber(l))
return 1;
nvalue(l) *= nvalue(r);
--top;
}
break;
栈顶两元素 top-2 和 top-1 相乘,top-1 出栈,结果保存在新的栈顶。
只在两个 Object 均可转化为数值型时该运算有效。
> DIVOP,
case DIVOP:
{
Object *l = top-2;
Object *r = top-1;
if (tonumber(r) || tonumber(l))
return 1;
nvalue(l) /= nvalue(r);
--top;
}
break;
栈顶两元素 top-2 和 top-1 相除,top-1 出栈,结果保存在新的栈顶。
只在两个 Object 均可转化为数值型时该运算有效。
> CONCOP,
case CONCOP:
{
Object *l = top-2;
Object *r = top-1;
if (tostring(r) || tostring(l))
return 1;
svalue(l) = lua_createstring (lua_strconc(svalue(l),svalue(r)));
if (svalue(l) == NULL)
return 1;
--top;
}
break;
栈顶两元素 top-2 和 top-1 字符串连接,top-1 出栈,结果保存在新的栈顶。
只在两个 Object 均可转化为字符串型时该运算有效。
连接结果是新生成的字符串,原来的两个字符串保持不变。
> MINUSOP
case MINUSOP:
if (tonumber(top-1))
return 1;
nvalue(top-1) = - nvalue(top-1);
break;
栈顶元素数值取反,只在其可转化为数值型时有效。
> NOTOP
case NOTOP:
tag(top-1) = tag(top-1) == T_NIL ? T_NUMBER : T_NIL;
break;
栈顶元素逻辑取反。
当栈顶元素为假(T_NIL)时设置其为真(T_NUMBER)。
当栈顶元素为真(非 T_NIL 型)时设置其为假(T_NIL)。
> ONTJMP
case ONTJMP:
{
CodeWord code;
get_word(code,pc);
if (tag(top-1) != T_NIL) pc += code.w;
}
break;
真跳转,如果判断栈顶元素为真则跳转,指令偏移量从字节码中取得。
> ONFJMP
case ONFJMP:
{
CodeWord code;
get_word(code,pc);
if (tag(top-1) == T_NIL) pc += code.w;
}
break;
假跳转,如果判断栈顶元素为假则跳转,指令偏移量从字节码中取得。
> JMP
case JMP:
{
CodeWord code;
get_word(code,pc);
pc += code.w;
}
break;
无条件跳转,指令偏移量从字节码中取得。
> UPJMP
case UPJMP:
{
CodeWord code;
get_word(code,pc);
pc -= code.w;
}
break;
向上无条件跳转,指令偏移量从字节码中取得。
> IFFJMP
case IFFJMP:
{
CodeWord code;
get_word(code,pc);
top--;
if (tag(top) == T_NIL) pc += code.w;
}
break;
假跳转,如果判断栈顶元素为假则跳转,指令偏移量从字节码中取得。
判断条件出栈。
> IFFUPJMP
case IFFUPJMP:
{
CodeWord code;
get_word(code,pc);
top--;
if (tag(top) == T_NIL) pc -= code.w;
}
break;
假跳转,如果判断栈顶元素为假则向上跳转,指令偏移量从字节码中取得。
判断条件出栈。
> POP
case POP: --top; break;
出栈。
> CALLFUNC
case CALLFUNC:
{
Byte *newpc;
Object *b = top-1;
while (tag(b) != T_MARK) b--;
if (tag(b-1) == T_FUNCTION)
{
lua_debugline = 0; /* always reset debug flag */
newpc = bvalue(b-1);
bvalue(b-1) = pc; /* store return code */
nvalue(b) = (base-stack); /* store base value */
base = b+1;
pc = newpc;
if (MAXSTACK-(base-stack) < STACKGAP)
{
lua_error ("stack overflow");
return 1;
}
}
else if (tag(b-1) == T_CFUNCTION)
{
int nparam;
lua_debugline = 0; /* always reset debug flag */
nvalue(b) = (base-stack); /* store base value */
base = b+1;
nparam = top-base; /* number of parameters */
(fvalue(b-1))(); /* call C function */
/* shift returned values */
{
int i;
int nretval = top - base - nparam;
top = base - 2;
base = stack + (int) nvalue(base-1);
for (i=0; i<nretval; i++)
{
*top = *(top+nparam+2);
++top;
}
}
}
else
{
lua_reportbug ("call expression not a function");
return 1;
}
}
break;
函数调用,从栈顶到栈中类型为 T_MARK 的 Object 均为函数参数。
类型为 T_MARK 的 Object 的下一个 Object 为函数名。
函数调用有两种:
一种为 Lua 脚本中定义的函数的调用,相应的 Object 类型为 T_FUNCTION。
另一种为 Lua 脚本中调用 C 写的函数,相应的 Object 类型为 T_CFUNCTION。
T_FUNCTION 调用前保存当前执行字节码 pc 和栈的 base 以做调用结束后的恢复,设置 pc 为调用函数的字节码地址即可。
T_CFUNCTION 调用前保存栈的 base 以做调用结束后的恢复,取得函数参数个数。
函数调用结束后,调整返回值的位置,恢复 top 和 base 的值。把返回值调整得和 Lua 函数返回的一样。
也就是原来函数 Object 和 T_MARK 的地方被返回值替掉。
可以看出来,这里的函数调用和汇编或者 C 语言里的函数调用的栈桢是长得很像的(除了没有寄存器)。
> RETCODE
case RETCODE:
{
int i;
int shift = *pc++;
int nretval = top - base - shift;
top = base - 2;
pc = bvalue(base-2);
base = stack + (int) nvalue(base-1);
for (i=0; i<nretval; i++)
{
*top = *(top+shift+2);
++top;
}
}
break;
拷贝返回值到函数调用前的位置,就是栈里 T_MARK 前面的那个函数类型的 Object 处。
当前的字节码保存的偏移量,通过计算 top, base, shift 之差得到返回值个数。 shift 是指函数有几个参数。
重置 top, pc, base。
把函数的返回值拷贝到栈上原来的函数 Object 处。
> HALT
case HALT:
base = oldbase;
return 0; /* success */
正常停止,重置栈。
> SETFUNCTION
case SETFUNCTION:
{
CodeWord file, func;
get_word(file,pc);
get_word(func,pc);
if (lua_pushfunction (file.w, func.w))
return 1;
}
break;
设置函数,函数的文件名和函数地址从字节码里取得。
> SETLINE
case SETLINE:
{
CodeWord code;
get_word(code,pc);
lua_debugline = code.w;
}
break;
设置 debug 行号。
> RESET
case RESET:
lua_popfunction ();
break;
弹出函数
来源:oschina
链接:https://my.oschina.net/u/105655/blog/313660