一、虚拟机设计方案

1.  架构风格

Python虚拟机实际上是一个解释器,对编译后的字节码进行解释、执行。因此解释器风格显然是最适合本项目的。

2.  分解视图

 

虚拟机输入为字节码.pyc文件,由字节码文件加载器将二进制的.pyc文件加载到内存,由执行引擎解释执行,输出为字节码文件的执行结果。虚拟机总共分为以下四个模块:

  • 字节码加载器:python字节码是按固定格式存放的二进制文件,而在虚拟机进程中,字节码对象是codeobject类型,加载器的作用就是在类型体系模块的支持下,将固定格式的二进制文件解析成内存中的codeobject类型对象,然后将codeobject交由执行引擎运行。
  • 执行引擎:本质是虚拟机的解释器部分,本次虚拟机设计为栈式执行,所以解释器维护一个操作栈,字节码所有的操作都在栈上执行。解释器主要运行在一个很大switch分支循环中,每个分支分别为对应字节码的解释,直到字节码执行结束跳出循环结束虚拟机。解释器还维护一个个虚拟机操作数栈帧frame,每个frame对应一个函数或方法的调用,且第一个frame为第一个codeobject。每个frame中有一个指向调用者frame的指针、当前frame字节码位置的pc、对应的codeobjcet等。在解释器中,在要操作栈上产生的类型对象都在堆中产生,依赖于堆区的内存管理,虚拟机可以不用管理对象的析构,而交由堆区自动垃圾回收。
  • 类型体系:在python中,一切都是对象,虚拟机有着一个庞大的类型体系。这个模块也是最基本最重要的模块,大致上有Integer、Float、String、List、Set、Dict、Tuple这7个基本类型,还有运行时的codeobject、frame,其他的内建类型type、function、method、slice、iterator、module等。还有一个特殊的类型object,它是虚拟机中大部分类型的父类。
  • 堆区内存管理:管理类型对象的关键,对象的分配权力交给了堆,在堆中使用自动内存管理算法,如标记-清除、标记-复制等算法。

3.  依赖视图

依赖视图展现了软件模块之间的依赖关系。

各个模块之间的依赖关系如下所示:

 

 

 字节码加载器部分分为两个类,他们之间不存在依赖关系:

 

Type类存放了对象的类型信息和对应的方法,Object类依赖于Type类,其他的基本类型都继承自Object类:

4.  执行视图

执行视图展示了系统运行时的时序结构特点。

 

5.  实现视图

实现视图是描述软件架构与源文件之间的映射关系。

虚拟机源代码目录的结构如下所示:

pvm/
├── bin
├── include
│   ├── Code.h
│   ├── Dict.h
│   ├── Float.h
│   ├── GlobalVar.h
│   ├── Integer.h
│   ├── List.h
│   ├── Object.h
│   ├── OpCode.h
│   ├── Str.h
│   ├── Type.h
│   └── global.h
├── main.c
├── objects
│   ├── Code.c
│   ├── Dict.c
│   ├── Float.c
│   ├── Integer.c
│   ├── List.c
│   ├── Object.c
│   └── Str.c
├── runtime
└── utils
    ├── FileLoader.c
    ├── FileLoader.h
    ├── FileReader.c
    ├── FileReader.h
    ├── Log.c
    └── Log.h

二、核心数据结构

Python2字节码文件结构

 

 

Magic number

 (4B)

Modified date

 (4B)

‘c‘

(1B,表示接下来是CodeObject)

 

Argcount

(4B)

Nlocals

(4B)

Stacksize

(4B)

Flags

(4B)

字节码

‘s‘

(1B)

字节码长度

(4B)

字节码1,字节码2 …

常量表

‘(‘

(1B)

常量个数

(4B)

常量1,常量2 …

变量表

‘(‘

(1B)

变量个数

(4B)

变量1,变量2 …

参数列表

‘(‘

(1B)

 

 

Cell var

‘(‘

(1B)

 

 

Free var

‘(‘

(1B)

 

 

文件名

‘s‘

(1B)

名字长度

(4B)

 

模块名

‘t‘

(1B)

模块名长度

(4B)

 

行号表(调试)

‘s‘

(1B)

 

 

 

三、运行环境和技术选型

Python是跨平台语言,其生成的字节码文件在不同平台上具有相同的结构,因此虚拟机的运行环境可以是Windows,Linux,macOS。虚拟机的开发语言定为C语言。

四、核心工作机制

以运行一个内容为 “print(1 + 2 * 3)” 的python源文件为例,假设源文件经过编译生成的字节码是a.pyc,要执行这个文件,需要先读取a.pyc中的字节码列表和常量表。a.pyc的字节码列表中有LOAD_CONST、BINARY_ADD、PRINT_ITEM、PRINT_NEWLINE等指令,常量表中有常量1和6,我们根据字节码列表中的指令,在操作数栈上进行对应操作:指令为LOAD_CONST时从常量表取出数字放进栈里面,指令为BINARY_ADD时就从栈中取出数字相加,指令为PRINT_ITEM就打印计算结果,这样就完成了对a.pyc的运行。

posted on 2020-12-30 18:50  xiop  阅读(747)  评论(0编辑  收藏  举报