1. 程式人生 > 實用技巧 >Python虛擬機器設計方案

Python虛擬機器設計方案

一、虛擬機器設計方案

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的執行。