首页 > 代码库 > Lua1.1 打印字节码

Lua1.1 打印字节码

如何打印出字节码:
代码里做如下修改,把打印字节码的宏开关打开。
y.tab.c
18 行
#define LISTING 0
改为
#define LISTING 1

因为 PrintCode 的定义在调用之后,所以加个前置声明:
做出下修改:
y.tab.c
329 行
添加
static void PrintCode (Byte *code, Byte *end);
保证在 lua_parse 调用它的时候,是已经声明了的。

把打印字节码打开之后,执行脚本的时候就会先打字节码打印出来。
看看字节码打印出来是什么样,还来个 hello, world 吧
--------------------------------
print("Lua1.1 show bytecode")
print("hello, world")
--------------------------------
打印字节码如下:
CODE
0 PUSHGLOBAL 4
3 PUSHMARK
4 PUSHSTRING 8
7 CALLFUNC
9 ADJUST 0
10 PUSHGLOBAL 4
13 PUSHMARK
14 PUSHSTRING 9
17 CALLFUNC
19 ADJUST 0
20 HALT
Lua1.1 show bytecode
hello, world
简单解释下,最后的两行是程序的执行结果,就是输出了两个字符串。
前的从 "CODE" 开始直到 “HALT”结束的都是字节码。
每行的最左边的标号字节码相对偏移量,右面的就是字节码了。
--------------------------------
现在,就可以解决在 Lua1.0 里说的那个 $debug 的问题了。
代码和上面的一样,除了在第一行加上 “$debug"。
--------------------------------
$debug
print("Lua1.1 show bytecode")
print("hello, world")
--------------------------------
打印字节码如下:
CODE
0 SETLINE 2
3 PUSHGLOBAL 4
6 PUSHMARK
7 PUSHSTRING 8
10 CALLFUNC
12 ADJUST 0
13 SETLINE 3
16 PUSHGLOBAL 4
19 PUSHMARK
20 PUSHSTRING 9
23 CALLFUNC
25 ADJUST 0
26 HALT
Lua1.1 show bytecode
hello, world
对比上面打印出来的字节码,可以看出区别了吧。 下面的字节码比上面多了 6 个字节。我们看到下面的字节码多了下面 2 句,
0 SETLINE 2
13 SETLINE 3
这个 SETLINE 后面的标号对应的就是源代码中的行号。这样,比较方便对比字节码和源代码。以后不特别说明的情况下,我们把每个脚本的头部都加上 "$debug" 来生成带源代码行号的字节码。

看了字节码,可以看出来一些问题,我们的 "hello, world" 这样的字符串跑哪儿去了?从字节码中体现不出来。
这个版本上,不可以直接执行编译好的字节码,每次执行脚本的时候,都得老老实实的从 Lua 脚本源代码编译执行,原因就在这里,看字节码里,这种字符串这样的数据信息丢失了。就是源代码转化为字节码后,字节码自己携带的信息要少于源代码。我们知道在写汇编程序时,一般会把程序分为数据段,代码段。在字节码这里,则相当于数据段没有了。那数据去哪儿了?数据在源代码编译为字节码中,保存到了环境里。而这样的情况直到 Lua2.4 的时候,字节码才可以保存下来,由解释器直接执行。这样的字节码是什么样的呢?我会不会分析一下呢?目前还没有这样的计划。不过也说不定。计划内的是 Lua5.x 之前,再分析一个 Lua4.0,因为那是 Lua 栈式虚拟机的最后一个版本。到 Lua5.0 就变成了寄存器式的虚拟机了。

我也尝试过在 Lua1.0 里打开打印字节码的功能,不过,效果很差,自带的几个例子中有不少看起来都像是死循环了,都大量的空指令(NOP,这是 Lua1.0 里的一个指令,空指令引入的本意是在对字节对齐有需求的体系架构上做为填充之用。不过实际上看来是没有用上, Lua1.1 里已经没有这个指令了。)和输出。

Lua1.1 打印字节码