此文诠释基本的 Python 虚拟机结构,以及主要的栈操作和帧调用。
并使用 Go 语言进行代码逻辑复验。
基于栈的虚拟机(Virtual Machine)
Python 是一门解释型语言,也是一门编译型语言,通过编译器把语法树分析成独有的字节码,从而再链接虚拟机执行字节码,而虚拟机整体架构和运行机制仅仅使用栈结构,非常简单理解的数据结构,但是怎么根据栈,字节码,实现变量、函数调用、类调用,是一个非常难以解释的问题。
栈可以理解成一个集合或一个列表,结构如下:Stack
FIFO:First in, First out(先进后出原则)
FILO:First in, Then out(先进先出原则)
其两种栈结构的区别在于:
// FIFOfor (int i = list.length; i > 0; i –) {} // 3 9 2 5// FILOfor (int i = 0; i < list.length; i ++) {} // 5 2 9 3
化简编译流程Process
首先源代码通过编译器(此处省略数个步骤)分析成帧对象,而帧对象内又包括代码对象。
主要结构是代码对象,代码对象内包含字节码列表,常量列表,变量列表,偏移量列表。
字节码偏移量
每个字节码只占用 1 byte,不包括后带的参数,如果有参数,其也占用 1 byte。名称参数作用
CONST1载入常量
LOAD1加载变量
STORE1赋给变量
ADD-执行加法
SUB-执行减法
MUL-执行乘法
DIV-执行除法
PUT-输出栈顶
POP-弹出栈顶
RET-返回栈顶
CALL形参数量执行函数
注:此字节码列表仅用于代码复验。
可以看出,一个 __code__对象内包含 .co_varnames 和 .co_consts,变量名和常量列表。
而偏移量列表则在字节码列表中,跟随在字节码后,我们用 Go 语言实现,则单独设定个偏移量列表。
虚拟机包含帧调用列表Frame Structure
虚拟机初始化第一个帧为全局帧,全局帧里包含标准方法(BUILTIN),例如
# 整型数据
# len 函数
全局声明的变量、函数、类、等,也包含在全局帧里,而后面加入的帧可以理解成块调用语句,新开的一个作用域,块与块之间的数据不一致。Frames 也是采用栈结构,栈顶是当前执行的帧。
虚拟机仅仅执行帧对象。
帧结构Structure
CODE:代码对象
DATA:计算栈
BLOCK:块栈
LOCAL:变量符号表
BUILTIN:内建符号表
块栈标识当前的循环执行、嵌套循环和异常退出,如果当前是 continue,那么块栈顶是loop,标识循环内的迭代器就应该保存在数据栈中,下次循环依旧是上次的迭代。
代码对象结构Structure
BYTECODE:字节码
CONSTANT:常量
VARIABLE:变量名
OFFSET:偏移量
偏移量标识了有参数的字节码的对象位置,例如 CONST 4,加载常量列表里第 5 个数据。
STORE 2,把栈顶的值赋给变量名列表里第 3 个变量名。
函数调用实例
两个帧实现函数参数传递和返回值传递。
// foo
BYTECODE: [
CONST, // 5
LOAD, // x
LOAD, // y
ADD, // x + y
MUL, // * 5
PUT, // 输出
RET // 返回
],
CONSTANT: [ None, 5 ],
VARAIBLE: [ ‘x’, ‘y’ ]
OFFSET: [
1, // 5
0 // x
1, // y
]
// main
BYTECODE: [
CONST, // 3
CONST, // 6
CONST, // foo
CALL, // 2
PUT, // 45
POP, // 销毁栈顶
RET // 执行完毕
],
CONSTANT: [ None, 3, 6, foo ],
VARAIBLE: [ ]
OFFSET: [
1, // 3
2 // 6
3, // foo
2, // CALL
]
函数参数传递首先 const 把函数加载出来(此处和 cpython 不同)
根据函数形参数量,pop 数据栈,得到参数,对比类型和其他错误。
把参数赋给函数代码对象里的 local variables,即符号表,此处完成函数体参数赋值。
函数代码对象如果有参数,位置始终从 var 栈 0 起始,函数体内再声明的变量依次排队。
函数返回值当虚拟机执行到 RET 字节码,把当前栈顶的值赋给当前帧的返回值对象。
函数执行(帧执行)完后,判断当前帧的返回值对象。
如果存在,则推入计算栈,得到返回值。
如 Python 在每个常量列表第一个值始终是 None,即无返回值,则返回 CONST 0 对应 None.
Python 中其他对象Process
To be continue…
Go 语言实现:bingxio/go-pyframegithub.com
如有帮助,请给个星!!
参考
今天的文章python frame用法_tkinter frame详解「建议收藏」分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/64270.html