7 Upvalues and Globals
rel="File-List" href="file:///C:%5CDOCUME%7E1%5CWangBo%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
当Lua虚拟机需要upvalue或者全局变量时,有相应的指令将值读取到寄存器中。同样,当upvalue或全局变量需要被写入的时候,同样用相应的指令可以使用。
| rel="File-List" href="file:///C:%5CDOCUME%7E1%5CWangBo%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
拷贝全局变量值到寄存器R(A),全局变量的名字由常量计数Bx给出。名字常量必须是字符串。
SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
将寄存器R(A)中的值拷贝到全局变量中,全局变量的名字由常量计数Bx给出,名字常量必须是字符串。 |
rel="File-List" href="file:///C:%5CDOCUME%7E1%5CWangBo%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
GETGLOBAL和SETGLOBAL指令非常只管,而且容易使用。指令要求全局变量名字是一个常量,由指令的域Bx索引。R(A)可以是源或目的寄存器。函数使用的全局变量的名字是函数的常量列表的一部分。
>a = 40; local b = a
; function [0] definition (level 1)
; 0 upvalues, 0 params, 2 stacks
.function 0 0 2 2
.local "b" ; 0
.const "a" ; 0
.const 40 ; 1
[1] loadk 0 1 ; 40
[2] setglobal 0 0 ; a
[3] getglobal 0 0 ; a
[4] return 0 1
; end of function
从这个例子中你可以看到“b”是局部变量,“a”是全局变量的名字。行[1]将数字40读取到寄存器0(起到临时寄存器的功能,因为局部变量b还没有被定义。) 行[2]将寄存器0中的值付给名字为“a” (常量0)的全局变量。当了行[3],局部变量b被定义,并且被赋值为全局变量a的值。
| rel="File-List" href="file:///C:%5CDOCUME%7E1%5CWangBo%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
GETUPVAL A B R(A) := UpValue[B]
将索引为B的upvalue值拷贝到寄存器R(A)中。每一个函数都可能会有自己的upvalue 列表。upvalue是虚拟机内部的;函数原型中的upvalue名字字符串列表不是必须的。 GETUPVAL操作码还有第二个个目标 – 它也被用在创建闭包中,通常添加在CLOSURE指令的后面;查看CLOSURE指令获得更多的信息。
SETUPVAL A B UpValue[B] := R(A)
将寄存器R(A)中的值拷贝到索引为B的upvalue中,这个upvalue位于函数的upvalue列表中。 |
rel="File-List" href="file:///C:%5CDOCUME%7E1%5CWangBo%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
GETUPVAL和SETUPVAL用来内部管理upvalue列表。函数原型中的upvalue名字列表是为了调试目的;它不会被Lua虚拟机使用并且可以用luac去掉。
在运行的时候,upvalues由CLOSURE创建,由Lua虚拟机维护。在下面的例子中,函数b被定义在主块中,在反汇编列表中以在函数原型中的函数原型的形式展示出来。
>local a; function b() a = 1 return a end
; function [0] definition (level 1)
; 0 upvalues, 0 params, 2 stacks
.function 0 0 2 2
.local "a" ; 0
.const "b" ; 0
; function [0] definition (level 2)
; 1 upvalues, 0 params, 2 stacks
.function 1 0 0 2
.upvalue "a" ; 0
.const 1 ; 0
[1] loadk 0 0 ; 1
[2] setupval 0 0 ; a
[3] getupval 0 0 ; a
[4] return 0 2
[5] return 0 1
; end of function
[1] closure 1 0 ; 1 upvalues
[2] move 0 0
[3] setglobal 1 0 ; b
[4] return 0 1
; end of function
在主函数块中(函数0,级别1),局部变量a的值开始是nil。在行[1]处的CLOSURE展示了带有一个upvalue,a的函数原型0(函数0,级别2)。行[2]是闭包的一部分,它将当前作用域中的局部变量a连接到闭包中的upvalue a。最后这个闭包被赋值给全局变量b。
在函数b中,有一个upvalue,a。在Pascal中,通过遍历栈结构来发现外围作用域的变量。但是,Lua函数实例是一类值,可以被赋值给变量并且在其他地方被引用。此外,一个原型可以具有多个实例。因此,域在Pascal中的遍历栈结构相比,管理upvalues变得更有技巧性。Lua虚拟机的解决方案是提供一个清晰的接口,通过GETUPVAL和SETUPVAL访问upvalues,同时upvalues的管理由虚拟机自身完成。
函数b中的行[2]将upvalue a(在upvalue表中upvalue计数为0)的值设置为数值1(保存在寄存器0中。)行[3]处,重新得到upvalue a的值并且将它放入到寄存器0中,接下来的RETURN指令将把它作为返回值来使用。行[5]的RETURN指令没有被使用。
本文介绍Lua虚拟机如何处理upvalue及全局变量的读取与写入操作,包括GETGLOBAL、SETGLOBAL、GETUPVAL和SETUPVAL等指令的具体应用。

4369

被折叠的 条评论
为什么被折叠?



