2009-11-28 49 views
4

我正在開發,編譯爲自己的虛擬機,一個簡單的具有指令以某種數據的工作像載體一種腳本語言,漂浮和等..存儲單元表示這樣:設計的虛擬機JIT

struct memory_cell 
{ 
    u32 id; 
    u8 type; 

    union 
    { 
     u8 b; /* boolean */ 
     double f; /* float */ 
     struct { double x, y, z; } v; /* vector */ 
     struct { double r, g, b; } c; /* color */ 
     struct { double r, g, b; } cw; /* color weight */ 
     struct { double x, y, z; } p; /* point variable */ 
     struct { u16 length; memory_cell **cells; } l; /* list variable */ 
    }; 
}; 

說明是通用的,可以在許多不同的操作數工作。例如

ADD dest, src1, src2 

可以使用浮點數,向量,點,顏色根據操作數設置正確類型的目標。

主執行週期只檢查指令的操作碼(它是一個包含用於定義任何類型指令的聯合的結構)並執行它。我使用了一種簡化的方法,其中我沒有寄存器,只有大量的存儲單元。

我想知道JIT是否可以幫助我獲得最佳表演或不如何實現它。

正如我說最好的執行已達成到目前爲止是這樣的事情:

void VirtualMachine::executeInstruction(instr i) 
{ 
    u8 opcode = (i.opcode[0] & (u8)0xFC) >> 2; 

    if (opcode >= 1 && opcode <= 17) /* RTL instruction */ 
    { 
     memory_cell *dest; 
     memory_cell *src1; 
     memory_cell *src2; 

     /* fetching destination */ 
     switch (i.opcode[0] & 0x03) 
     { 
      /* skip fetching for optimization */ 
      case 0: { break; } 
      case MEM_CELL: { dest = memory[stack_pointer+i.rtl.dest.cell]; break; } 
      case ARRAY_VAL: { dest = memory[stack_pointer+i.rtl.dest.cell]->l.cells[i.rtl.dest.index]; break; } 
      case ARRAY_CELL: { dest = memory[stack_pointer+i.rtl.dest.cell]->l.cells[(int)i.rtl.dest.value]; break; } 
     } 

    /* omitted code */ 

    switch (opcode) 
    { 
     case ADD: 
     { 
      if (src1->type == M_VECTOR && src2->type == M_VECTOR) 
      { 
       dest->type = M_VECTOR; 
       dest->v.x = src1->v.x + src2->v.x; 
       dest->v.y = src1->v.y + src2->v.y; 
       dest->v.z = src1->v.z + src2->v.z; 
       } 

     /* omitted code */ 

是否容易/便利嘗試JIT編譯?但我真的不知道從哪裏開始,這就是爲什麼我要問一些建議。

除此之外,還有什麼其他的建議,我應該考慮在開發它?

這個虛擬機應該足夠快,可以爲光線追蹤器計算着色器,但我還沒有做過任何一種基準測試。

+0

一個很好的鍛鍊確實......但爲什麼另起爐竈?已經有很多很棒的VM:LLVM,JVM,BEAM(Erlang Emulator)等等。 – jldupont 2009-11-28 12:24:55

+4

因爲理解這些主題的內幕很有趣.. – Jack 2009-12-01 15:36:56

+0

我之前忘了提及這個,但是你見過OpenCL嗎? (http://www.khronos.org/opencl/)可能會給你一些想法。 – 2009-12-01 17:09:05

回答

7

在編寫JIT(「Just-in-time」)編譯器之前,您至少應該考慮如何編寫一個「先行先試」編譯器。

也就是說,給定包括你的虛擬機指令的程序,你會如何產生節目由86(或其他)的指令,即不一樣的原始程序?你將如何優化不同指令集的輸出,以及同一架構的不同版本?您提供的示例操作碼具有相當複雜的實現,那麼您可以通過發送執行該任務的代碼來實現「內聯」操作碼,以及通過發出對某些共享代碼的調用來實現哪種操作碼?

JIT必須能夠做到這一點,並且它還必須在VM運行時確定它執行的代碼,何時執行代碼以及它如何表示由此產生的VM指令和原生指令。

如果你還不是組裝騎師,那麼我不建議你寫一個JIT。這並不是說「永遠不要做」,但你應該在認真開始之前成爲組裝騎師。

另一種是寫一個非JIT編譯器轉換你的虛擬機指令(或原始腳本語言)爲Java字節碼,或LLVM,傑夫福斯特說。然後讓該字節碼的工具鏈完成難以處理的CPU工作。

6

虛擬機是一個值得考慮的重要任務。你有沒有考慮過像LLVM這樣的虛擬機?

LLVM將爲您提供一個良好的基礎,並有大量example projects,您可以使用它來了解。

3

Steve Jessop有一個觀點:JIT編譯器比正常編譯器更難。 正常的編譯器本身很難。

但是,閱讀問題的最後一部分,我不知道如果你真的想要一個JIT編譯器。

如果你的問題是這樣的:

我想創建一個光線追蹤程序,它允許用戶用自己的領域特定語言提供他們的着色器程序等 。 它確定。 我有我的語言定義,解釋器實施,它的作品很好,正確。 但它很慢:我如何將它作爲本機代碼執行?

那麼這裏是我以前做的是類似的情況:

  • 翻譯你的用戶提供的程序,以C函數,可以在程序中調用。

  • 寫出來正常的C源文件以適當的#includes等

  • 如.DLL(或.so在* nix中),使用普通的C編譯器編譯它們。

  • 在您的程序中動態加載.dll文件,找到您的函數指針並在您的光線跟蹤器中使用它們代替解釋版本 。

一些注意事項:

  • 在某些環境下可能是不可能的:C編譯器或系統策略 進不去不容許你加載你自己的DLL。 因此請在嘗試之前進行檢查。

  • 不要丟棄你的解釋器。 保持它作爲您的語言的參考實現。

+0

「(愚蠢但它發生)」。看起來有點奇怪有一個C編譯器,但沒有動態鏈接。但是根本沒有C編譯器是很常見的,如果你考慮到大多數代碼不能在個人電腦上運行...... – 2009-12-01 17:15:04

+0

@Steve:我想我會刪除這條評論。這是關於限制使用自己的代碼(exe,dll等)作爲系統策略的權利,而不是缺乏編譯器。 我知道它發生了。 無論如何,如果用戶無法加載自己的(而不是由管理員安裝的)代碼,那麼合併JIT的程序也需要以某種方式提升權限。 在某些環境中,您將無法將數據塊作爲二進制代碼執行(防止緩衝區溢出等),因此無論如何您都需要將其作爲共享庫加載。 – 2009-12-01 17:35:25

+0

是或取決於系統,它可能是另一種方式--JIT可以分配具有中級特權的可執行內存,但它需要數字簽名(或內核級特權)才能授權加載dll。我只能假設,任何人都足夠聰明地寫一個JIT並展示它的工作原理,足夠聰明,不會將惡意代碼寫入內存並執行它。鑑於任何傻瓜可以加載一個圖書館,因此不應該被允許;-) – 2009-12-01 18:13:59