【转】: 探索Lua5.2内部实现:虚拟机指令(2) MOVE & LOAD
name | args | desc |
---|---|---|
OP_MOVE | A B | R(A) := R(B) |
OP_MOVE用来将寄存器B中的值拷贝到寄存器A中。由于Lua是register based vm,大部分的指令都是直接对寄存器进行操作,而不需要对数据进行压栈和弹栈,所以需要OP_MOVE指令的地方并不多。最直接的使用之处就是将一个local变量复制给另一个local变量时:
local a;
local b = a;
在编译过程中,Lua会将每个local变量都分配到一个指定的寄存器中。在运行期,lua使用local变量所对应的寄存器id来操作local变量,而local变量的名字除了提供debug信息外,没有其他作用。
在这里a被分配给register 0,b被分配给register 1。第二行的MOVE表示将a(register 0)的值赋给b(register 1)。其他使用的地方基本都是对寄存器的位置有特殊要求的地方,比如函数参数的传递等等。
name | args | desc |
---|---|---|
OP_LOADK | A Bx | R(A) := Kst(Bx) |
LOADK将Bx表示的常量表中的常量值装载到寄存器A中。很多其他指令,比如数学操作指令,其本身可以直接从常量表中索引操作数,所以可以不依赖于LOADK指令。
local a=1;
local b="foo";
name | args | desc |
OP_LOADKX | A | R(A) := Kst(extra arg) |
LOADKX是lua5.2新加入的指令。当需要生成LOADK指令时,如果需要索引的常量id超出了Bx所能表示的有效范围,那么就生成一个LOADKX指令,取代LOADK指令,并且接下来立即生成一个EXTRAARG指令,并用其Ax来存放这个id。5.2的这个改动使得一个函数可以处理超过262143个常量。
name | args | desc |
OP_LOADBOOL | A B C | R(A) := (Bool)B; if (C) pc++ |
LOADBOOL将B所表示的boolean值装载到寄存器A中。B使用0和1分别代表false和true。C也表示一个boolean值,如果C为1,就跳过下一个指令。
local a = true;
1 [1] LOADBOOL 0 1 0
2 [1] RETURN 0 1
C在这里的作用比较特殊。要了解C的具体用处,首先要知道lua中对于逻辑和关系表达式是如何处理的,比如:
对于上面的代码,一般我们会认为lua应该先对1<2求出一个boolean值,然后放入到a中。然而实际上产生出来的代码为:
1 [1] LT 1 -1 -2 ; 1 2
2 [1] JMP 0 1 ; to 4
3 [1] LOADBOOL 0 0 1
4 [1] LOADBOOL 0 1 0
5 [1] RETURN 0 1
onstants (2) for 0x80048eb0:
1 1
2 2
可以看到,lua生成了LT和JMP指令,另外再加上两个LOADBOOL对于a赋予不同的boolean值。LT(后面会详细讲解)指令本身并不产生一个boolean结果值,而是配合后面紧跟的JMP实现true和false的不同跳转。如果LT评估为true,就继续执行,也就是执行到JMP,然后调转到4,对a赋予true;否则就跳过下一条指令到达第三行,对a赋予false,并且跳过下一个指令。所以上面的代码实际的意思被转化为:
local a;
if 1 < 2 then
a = true;
else
a = false;
end
逻辑或者关系表达式之所以被设计成这个样子,主要是为if语句和循环语句所做的优化。不用将整个表达式估值成一个boolean值后再决定跳转路径,而是评估过程中就可以直接跳转,节省了很多指令。
C的作用就是配合这种使用逻辑或关系表达式进行赋值的操作,他节省了后面必须跟的一个JMP指令。
name | args | desc |
OP_LOADNIL | A B | R(A), R(A+1), ..., R(A+B) := nil |
LOADNIL将使用A到B所表示范围的寄存器赋值成nil。用范围表示寄存器主要为了对以下情况进行优化:
local a,b,c;
1 [1] LOADNIL 0 2
2 [1] RETURN 0 1
对于连续的local变量声明,使用一条LOADNIL指令就可以完成,而不需要分别进行赋值。
对于一下情况
local a;
local b = 0;
local c;
1 [1] LOADNIL 0 0
2 [2] LOADK 1 -1 ; 0
3 [3] LOADNIL 2 0
在Lua5.2中,a和c不能被合并成一个LOADNIL指令。所以以上写法理论上会生成更多的指令,应该予以避免,而改写成
【转】: 探索Lua5.2内部实现:虚拟机指令(2) MOVE & LOAD的更多相关文章
- 【转】: 探索Lua5.2内部实现:虚拟机指令(1) 概述
Lua一直把虚拟机执行代码的效率作为一个非常重要的设计目标.而采用什么样的指令系统的对于虚拟机的执行效率来说至关重要. Stack based vs Register based VM 根据指令获取操 ...
- 【转】: 探索Lua5.2内部实现:虚拟机指令(3) Upvalues & Globals
在编译期,如果要访问变量a时,会依照以下的顺序决定变量a的类型: a是当前函数的local变量 a是外层函数的local变量,那么a是当前函数的upvalue a是全局变量 local变量本身就存在于 ...
- JAVA安装过程中出现的“javac不是内部或外部指令”的解决方法
近来重新安装了JAVA,安装过程中出现问题,网上找到解决办法,汇总发布. 解决流程: 1.确定自己的环境变量设置没问题,没有出现遗漏 : . 等情况 (具体环境变量设置百度) 2.环境变量设置后 ,d ...
- Javac不是内部或外部指令
JDK安装完,命令行窗口中运行Java正常,运行Javac显示不是内部或外部指令 不存在百度上说的没有安装JDK,只安装了JRE 我的电脑是64位Win7操作系统 第一次安装的JDK不是从官网下载的, ...
- 从虚拟机指令执行的角度分析JAVA中多态的实现原理
从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧 ...
- Atitit .jvm 虚拟机指令详细解释
Atitit .jvm 虚拟机指令详细解释 1. 一.未归类系列A1 2. 数据mov系列2 2.1. 二.const系列2 2.2. 三.push系列2 2.3. ldc系列 该系列命令负责把数值常 ...
- Java SE7虚拟机指令操作码助记符
本文转载自Java SE7 虚拟机指令操作码助记符 导语 在Class文件中,Java方法里的方法体,也就是代表着一个Java源码程序中程序的部分存储在方法表集合的Code属性中.存储在Code属性中 ...
- 深入探索.NET框架内部了解CLR如何创建运行时对象
原文地址:http://msdn.microsoft.com/en-us/magazine/cc163791.aspx 原文发布日期: 9/19/2005 原文已经被 Microsoft 删除了,收集 ...
- JVM虚拟机指令
参考及转载: (1)https://blog.csdn.net/qq_33301113/article/details/73717855 (2)https://blog.csdn.net/wangxf ...
随机推荐
- ubuntu上建立本地git 和 网络 github的上传与下载
github工具是一个很好用的工具,可以在本地建立一个git仓库,存储当前写的程序或者数据,然后通过ssh与github建立联系.具体怎么实现,下面进行介绍. 1.首先要安装git 软件 在Linux ...
- MySql服务未知原因消失了的解决办法
一: 5.1及后续版本: 打开计算机命令窗口,切换至mysql安装目录,然后运行bin目录下的mysqld.exe,命令如下: D:\MySQL\bin>mysqld.exe -installS ...
- 【js】Object.prototype.hasOwnProperty()
hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性 例如:obj.hasOwnProperty(prop) 1. 所有 Object 的对象都会有 hasOw ...
- jQuery 属性操作 - addClass() 和 removeClass() 方法
实例 向第一个 p 元素添加一个类: $("button").click(function(){ $("p:first").addClass("int ...
- 20181029NOIP模拟赛T2
2.追捕 [题目背景] Duan2baka:“jmsyzsfq天下第一蠢!” jmsyzsfq:“你说什么?!” [题目描述] 于是Duan2baka开始了逃亡的旅程,而jmsyzsfq也开始追捕Du ...
- .Net core 使用SSH.Net上传到SFTP服务器和和下载文件
今天换了个服务器,文件上传到sftp服务器上了,那么ftp和sftp服务器有什么区别呢,正常来说sftp会更安全一些. 废话不多说,首先.net core 上传到sftp需要引入一个Nuget包,就是 ...
- Flask中那些特殊的装饰器
模板相关的装饰器 @app.template_global() 用法: @app.template_global() # 记得加括号 def jiafa(a, b): # 这个方法每调用一次就需要传一 ...
- C++函数调用之——值传递、指针传递、引用传递
1.简介 1.值传递:形参时实参的拷贝,改变函数形参并不影响函数外部的实参,这是最常用的一种传递方式,也是最简单的一种传递方式.只需要传递参数,返回值是return考虑的:使用值传递这种方式,调用函数 ...
- 【数据结构】循环链表&&双向链表详解和代码实例
喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 循环链表 1.1 什么是循环链表? 前面介绍了单链表,相信大家还记得相关的概念.其实循环链表跟单链表也没有差别很多,只是在 ...
- python2.7入门---CGI编程&表单操作&cookie操作
看到标题我们首先有个疑问,什么是CGI?CGI 目前由NCSA维护,NCSA定义CGI为:CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上 ...