2011-06-21 83 views
22

我們正在爲高級編譯語言編寫一個字節碼,經過一些分析和優化後,很明顯,當前最大的性能開銷是我們使用的switch語句跳轉到字節碼的情況。標籤地址(MSVC)

我們調查了拔出每個案例標籤的地址並將其存儲在字節碼本身的流中,而不是我們通常打開的指令ID。如果我們這樣做了,我們可以跳過跳轉表,直接跳到當前正在執行的指令的代碼位置。這在GCC中非常有效,但是,MSVC似乎不支持這樣的功能。

我們試圖使用內聯彙編來獲取標籤的地址(並跳轉到它們),並且它可以工作,但是,使用內聯彙編會導致MSVC優化器避免整個函數。

有沒有辦法讓優化器仍然運行代碼?不幸的是,我們不能將內聯程序集提取到另一個函數中,而不是標籤所在的函數,因爲即使在內聯程序集中,也無法爲另一個函數引用標籤。任何想法或想法?非常感謝您的意見,謝謝!

+3

您是否嘗試過函數指針? –

+0

如何在字節碼中放置函數地址而不是標籤地址?然後,每個指令ID都有一個函數。除非你的獲取執行循環在你的大功能標籤中。 –

+0

如果我使用每種情況下的函數,並使用函數指針而不是標籤地址,它將起作用。但是,我覺得函數調用的開銷會非常大,即使函數是微不足道的(無參數,不返回),也會使性能增益無效。我會嘗試一下,並感謝張貼。 – Trevor

回答

15

在MSVC這樣做的唯一方法是使用內聯彙編(這基本上傢伙,你針對x64):

int _tmain(int argc, _TCHAR* argv[]) 
{ 
case_1: 
    void* p; 
    __asm{ mov [p],offset case_1 } 
    printf("0x%p\n",p); 
    return 0; 
} 

如果你打算做這樣的事情,那麼最好的辦法是寫整個解釋器在彙編中,然後通過鏈接器連接到主要的二進制文件(這是LuaJIT做的,這是虛擬機非常快速的主要原因,當它沒有運行JIT'ed代碼時)。

LuaJIT is open-source,所以你可能會從中選擇一些提示,如果你走的路線。或者,您可能需要查看第四個源代碼(其創建者開發的the principle您正在嘗試使用),如果有MSVC版本,您可以看到它們是如何實現的,否則您會被GCC卡住(其中並不是這樣, t是一件壞事,它適用於所有主要平臺)。

3

看來你可以將實際的代碼移動到函數而不是案例標籤。字節碼然後可以簡單地轉換成直接調用。即字節碼1將轉換爲CALL BC1。由於您正在生成直接調用,因此您沒有函數指針的開銷。大多數CPU的管道可以遵循這種無條件的直接分支。因此,每個字節代碼的實際實現都經過優化,從字節代碼到machince代碼的轉換是一個微不足道的1:1轉換。由於每個CALL都是5個字節(假設爲x86-32),所以您得到了一些代碼擴展,但這不太可能是一個主要問題。