2.Lua指令基础

2 Lua指令基础

The Lua virtual machine instruction set we will look at is a particular implementation of the Lua language. It is by no means the only way to skin the chicken. The instruction set just happens to be the way the authors of Lua chose to implement version 5 of Lua. The following sections are based on the instruction set used in Lua 5.1. The instruction set might change in the future – do not expect it to be set in stone. This is because the implementation details of virtual machines are not a concern to most users of scripting languages. For most applications, there is no need to specify how bytecode is generated or how the virtual machine runs, as long as the language works as advertised. So remember that there is no official specification of the Lua virtual machine instruction set, there is no need for one; the only official specification is of the Lua language.

我们将看到的Lua虚拟机指令集,是Lua语言的一个特别的实现。它并不是实现的唯一方式。Lua的作者碰巧选择指令集作为Lua版本5的实现。下面的章节是基于Lua5.1的指令集。指令集将来有可能改变——不能期望它一成不变。这是因为虚拟机的实现细节不是脚本编写者关心的。在大部分的应用中,没有必要说明字节码是如何产生的,或者虚拟机是如何运行的,只要Lua语言按它说明的工作就行。因此记住:没有官方的Lua虚拟机指令集的说明,这也没有必要。仅有的官方说明是关于Lua语言的。

 

In the course of studying disassemblies of Lua binary chunks, you will notice that many generated instruction sequences aren’t as perfect as you would like them to be. This is perfectly normal from an engineering standpoint. The canonical Lua implementation is not meant to be an optimizing bytecode compiler or a JIT compiler. Instead it is supposed to load, parse and run Lua source code efficiently. It is the totality of the implementation that counts. If you really need the performance, you are supposed to drop down into native C functions anyway.

在学习Lua字节码块的反汇编的过程中,你会发现许多产生的字节码流没有你想像的那么好。从工程的角度而言,这也是很正常的。规范的Lua实现并不意味着优化字节码编译器或者JITJust-In-Time)编译器。实际上,它只是有效的加载,解析和运行Lua源代码。它就是这些实现的全部。如果你真的要考虑性能,无论如何你都应该深入到本地的C函数里。

 

Lua instructions have a fixed size, using a 32 bit unsigned integer data type by default. In binary chunks, endianness is significant, but while in memory, an instruction can be portably decoded or encoded in C using the usual integer shift and mask operations. The details can be found in lopcodes.h, while the Instructiontype definition is defined in llimits.h.

Lua指令拥有固定大小,默认使用32位无符号整型。在代码块中,字节顺序是重要的,但是在内存中,在C语言中使用整型移动和掩码操作,指令可以方便的解码或编码。详细的可以参考文件lopcodes.h,而指令类型定义在文件llimits.h中。

 

There are three instruction types and 38 opcodes (numbered 0 through 37) are currently in use as of Lua 5.1. The instruction types are enumerated as iABC, iABx, iAsBx, and may be visually represented as follows:

Lua5.1中,当前使用三种指令类型和38个编码(037)。指令类型可以枚举为:iABC, iABx, iAsBx,同时按下图方式组织:

 (略)

Instruction fields are encoded as simple unsigned integer values, except for sBx. Field sBx can represent negative numbers, but it doesn’t use 2s complement. Instead, it has a bias equal to half the maximum integer that can be represented by its unsigned counterpart, Bx. For a field size of 18 bits, Bx can hold a maximum unsigned integer value of 262143, and so the bias is 131071 (calculated as 262143 >> 1). A value of -1 will be encoded as (-1 + 131071) or 131070 or 1FFFE in hexadecimal.

除了sBx,指令字段按简单的无符号整型值编码。sBx段可以代表负数,但是不能使用2s补充。取而代之的是,它有最大整数一半的偏差,这可以用它的对应部分Bx表示。字段的大小有18位,Bx能存储最大的无符号整型值262143,同时偏差为131071(通过262143 >> 1计算)。值为-1的数可以编码为(-1 + 131071)131070或十六进制的1FFFE

 

Fields A, B and C usually refers to register numbers (I’ll use the term “register” because of its similarity to processor registers). Although field A is the target operand in arithmetic operations, this rule isn’t always true for other instructions. A register is really an index into the current stack frame, register 0 being the bottom-of-stack position.

字段ABC通常只寄存器的数字(我使用词“寄存器”是因为它和处理器的寄存器相似)。虽然字段A在算数操作中是目标操作数,但并未适用于其它指令。寄存器实际上是当前栈帧的索引值,寄存器0是栈底位置。

 

Unlike the Lua C API, negative indices (counting from the top of stack) are not supported. For some instructions, where the top of stack may be required, it is encoded as a special operand value, usually 0. Local variables are equivalent to certain registers in the current stack frame, while dedicated opcodes allow read/write of globals and upvalues. For some instructions, a value in fields B or C may be a register or an encoding of the number of a constant in the constant pool. This will be described further in the section on instruction notation.

LuaC API不同,负索引(从栈顶计算)并不支持。对一些指令而言,栈顶值是必须的,它被编码成特别的操作数值,通常是0。局部变量相当于当前栈帧确定的寄存器,然而专用的编码允许读/写全局变量和上值。对某些指令而言,字段BC的值也许是寄存器或常量池中常量的数字编码。这将在指令说明的章节中进一步描述。

 

By default, Lua has a maximum stack frame size of 250. This is encoded as MAXSTACK in llimits.h. The maximum stack frame size in turn limits the maximum number of locals per function, which is set at 200, encoded as LUAI_MAXVARS in luaconf.h. Other limits found in the same file include the maximum number of upvalues per function (60), encoded as LUAI_MAXUPVALUES, call depths, the minimum C stack size, etc. Also, with an sBx field of 18 bits, jumps and control structures cannot exceed a jump distance of about 131071.

默认情况下,Lua拥有最大的栈帧大小为250。这个值定义为文件llimits.hMAXSTACK。最大的栈帧大小反过来限制了函数的最大的局部变量,这被设为200,位于luaconf.h中的LUAI_MAXVARS。此文件中可以发现其他的限制,这包括:函数的最大上值的个数(60LUAI_MAXUPVALUES、调用深度、C代码栈的最小值等等。同样,sBx字段是18位,跳转和控制结构不能超过131071

 

A summary of the Lua 5.1 virtual machine instruction set is as follows:

Lua5.1虚拟机指令集的简单描述如下表所示:

 

Opcode

Name

Description

0

MOVE

Copy a value between registers

1

LOADK

Load a constant into a register

2

LOADBOOL

Load a boolean into a register

3

LOADNIL

Load nil values into a range of registers

4

GETUPVAL

Read an upvalue into a register

5

GETGLOBAL

Read a global variable into a register

6

GETTABLE

Read a table element into a register

7

SETGLOBAL

Write a register value into a global variable

8

SETUPVAL

Write a register value into an upvalue

9

SETTABLE

Write a register value into a table element

10

NEWTABLE

Create a new table

11

SELF

Prepare an object method for calling

12

ADD

Addition operator

13

SUB

Subtraction operator

14

MUL

Multiplication operator

15

DIV

Division operator

16

MOD

Modulus (remainder) operator

17

POW

Exponentiation operator

18

UNM

Unary minus operator

19

NOT

Logical NOT operator

20

LEN

Length operator

21

CONCAT

Concatenate a range of registers

22

JMP

Unconditional jump

23

EQ

Equality test

24

LT

Less than test

25

LE

Less than or equal to test

26

TEST

Boolean test, with conditional jump

27

TESTSET

Boolean test, with conditional jump and assignment

28

CALL

Call a closure

29

TAILCALL

Perform a tail call

30

RETURN

Return from function call

31

FORLOOP

Iterate a numeric for loop

32

FORPREP

Initialization for a numeric for loop

33

TFORLOOP

Iterate a generic for loop

34

SETLIST

Set a range of array elements for a table

35

CLOSE

Close a range of locals being used as upvalues

36

CLOSURE

Create a closure of a function prototype

37

VARARG

Assign vararg function arguments to registers

 

Opcode

Name

Description

0

MOVE

寄存器间拷贝值

1

LOADK

加载一个常量到寄存器中

2

LOADBOOL

加载一个布尔值到寄存器中

3

LOADNIL

加载nil值到一定范围内的寄存器中

4

GETUPVAL

读取上值到寄存器中

5

GETGLOBAL

读取全局变量到寄存器中

6

GETTABLE

读取表成员到寄存器中

7

SETGLOBAL

将寄存器中的值写到全局变量中

8

SETUPVAL

将寄存器中的值写到上值中

9

SETTABLE

将寄存器中的值写到表成员中

10

NEWTABLE

创建一个新的表

11

SELF

准备对象的方法供调用

12

ADD

加法操作符

13

SUB

减法操作符

14

MUL

乘法操作符

15

DIV

除法操作符

16

MOD

取模(求余)操作符

17

POW

求幂操作符

18

UNM

取负操作符

19

NOT

逻辑非操作符

20

LEN

取长度操作符

21

CONCAT

连接一定范围的寄存器

22

JMP

无条件跳转

23

EQ

相等测试

24

LT

小于测试

25

LE

小于等于测试

26

TEST

布尔测试,附加条件跳转

27

TESTSET

布尔测试,附加条件跳转和赋值

28

CALL

调用闭合函数

29

TAILCALL

执行尾调用

30

RETURN

从函数调用中返回

31

FORLOOP

迭代数字的for循环

32

FORPREP

初始化数字的for循环

33

TFORLOOP

迭代泛化的for循环

34

SETLIST

设置数组中一定范围内的元素到表中

35

CLOSE

关闭一定范围用作上值的局部变量

36

CLOSURE

创建函数原型的闭包

37

VARARG

分配变参函数的参数到寄存器中

 

 

 

参考资料

1.         skin the chicken

http://www.iciba.com/skin%20the%20chicken/

set in stone

http://www.iciba.com/set%20in%20stone/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值