lua源码分析之性能分析1(赋值研究)

来源:互联网 发布:淘宝网上怎么买处方药 编辑:程序博客网 时间:2024/05/24 05:50
    lua中可以这样赋值:
        local a = 0;
        local b = 1;
        local c = 2;
        local d,e = a, b , c;
    也就是多个值给多个变量赋值。
    这篇文章就是分析这个赋值的效率的。
    前面写过一篇文章,叫“lua源码分析”,里面讲了lua怎么解析定义局部变量并生成指令的。
    这篇文章内容基于那篇文章,但那篇文章更注重源码分析,这篇文章重点是介绍一件事情。

    首先,讲一些东西。不知道怎么安排语言,随便说了。
    lua程序是运行在lua虚拟机上的。当虚拟机运行lua程序时,会接受一个Lua_State数据结构的对象。这个东西相当于一个线程,里面记载了lua程序所需要的所有信息。当然,lua解析器生成的中间码也保存在这个lua_State对象中。具体说来, 是当通过do_file()函数或do_string()函数执行一段lua代码的时候,lua会把这一整块代码当作一个函数。对的,比如,lua要执行一个a.lua文件,lua会把这个文件里的所有代码当作一个函数来解析和执行。在解析之前,lua会调用open_func()来创建一个Func_State的数据结构,这个数据结构是lua解析器进行语法分析时的东西,代表一个函数。lua创建了这个代表函数的数据结构,然后把要执行的代码生成的指令保存在这个数据结构中。
    lua每解析一个函数,都会创建一个Func_State数据结构的对象,然后将这个函数生成的指令存在这个数据结构中。这个数据结构是一个链表的形式,也就是说,每个Func_State数据结构中都包含一个数组,这个数组里保存着在这个函数里定义的局部函数。因为前面说了,lua会在解析之前创建一个Func_State数据结构对象,那么,在代码里定义的局部函数(以local开头)都是这个函数的局部函数,保存在这个函数数据结构中(语言组织的实在一塌糊涂,而且还没有表达清楚,好像还有误,不管了)。
    在lua运行期间,有一个栈,是lua_State数据结构的一个成员,由lua_state->base、lua_state->stack、lua_state->top组成。其中,lua_state->stack指向栈底,lua_state->top指向栈顶,lua_state->base指向当前执行函数的栈底,就像intel指令执行时,ebp指向当前指向函数的栈底。intel指令调用函数的时候,会首先将函数的栈底保存在ebp中,然后移动esp在栈中开辟一段空间,用于储存函数的局部变量。在lua中类似,局部变量是贮存在栈里的。而且每个函数都有自己对应的栈空间。而且,在lua的栈中,只贮存函数的局部变量。比如:一个函数的栈开始处假设在base处,那么,从base开始,lua解析这个函数的时候,没遇到一个由local定义的局部变量或局部函数,就会在栈里对应位置将其保留,也就是,如果第一个遇到的局部变量是a,那么base处储存的就是a,lua并不会在内部指明一个函数的每个局部变量放在栈的哪个位置,而是通过一个默认值,就是,如果一个函数在栈里的开始位置在base,那么base+n处就对应这个函数的第n+1个局部变量。
    前面讲了那么多,也就想说明一个问题,那就是lua中的函数的局部变量存在栈里。
    好了,进入正题,比如我们最前面那个例子。假设这个函数开始在栈中的位置是0。那么,局部变量a就存在栈的0号位置,b在1号,c在2号,也就是会生成以下代码(LOADK是指加载一个常量到一个寄存器中):
    1、local a = 0; ------   LOADK 0 0
    2、local b = 1; ------   LOADK 1 1
    3、local c = 2; ------   LOADK 2 2
    对于第4句,新建两个局部变量,并用3个局部变量给其赋值,这时候,其实是用前两个给其赋值的,第3个赋值的会被忽略掉。但是lua怎么处理这种情况呢?
    lua 会遍历等号“=”右边的东西,遇到一个东西,就生成一条赋值指令,也就是,在我们的例子中,lua会生成:
    4、local d , e = a , b ,c
                   --------- OP_MOVE 3 0(这里因为不是用常量赋值,而是用已定义的局部变量赋值,所以用MOVE,把第一个寄存器中的值赋值到第4个寄存器中,同理,如下)
                   --------- OP_MOVE 4 1
                   --------- OP_MOVE 5 2
    这里注意!问题来了!
    发现这里生成了3条指令,但是给2个变量赋值!所以多出来了一条指令!lua这时候是不管的,这条多出来的指令也会被执行!lua在这里的处理是,这条指令是会被执行,但是,寄存器4,也就是第5个寄存器还是被当作空闲寄存器用的,也就是,lua会忽略这个赋值操作,就当没使用过那个寄存器一样。
    其实,在解析代码的时候,完全可以不生成多余的指令,只要一个简单的判断就可以了。希望lua后续的版本会增加:)。