我想了解在執行程序過程中的實際區別解碼與調度解釋與線程解釋。解碼與調度解釋與線程解釋
這兩者的例子將真正幫助。
我瞭解Java字節碼的工作方式以及彙編語言的工作原理。但是DDI和TI適合在哪裏?
語境:Virtual machines: versatile platforms for systems and processes
我想了解在執行程序過程中的實際區別解碼與調度解釋與線程解釋。解碼與調度解釋與線程解釋
這兩者的例子將真正幫助。
我瞭解Java字節碼的工作方式以及彙編語言的工作原理。但是DDI和TI適合在哪裏?
語境:Virtual machines: versatile platforms for systems and processes
(注:我假設,通過「解碼和派發」你的意思是基於交換機的解釋。)
在基於交換機和螺紋解釋之間的區別運行時間基本上是執行的跳轉次數。
在基於開關的解釋器中,指令在某個中心位置被解碼,並根據解碼結果對處理解碼指令的代碼段執行跳轉。一旦這段代碼完成了對指令的解釋,它就跳回到集中解碼代碼,然後繼續執行下一條指令。這意味着每個解釋指令至少執行兩次跳轉。下面的C代碼塊說明了這樣的解釋可能是什麼樣子:
typedef enum {
add, /* ... */
} instruction_t;
void interpret() {
static instruction_t program[] = { add /* ... */ };
instruction_t* pc = program;
int* sp = ...; /* stack pointer */
for (;;) {
switch (*pc++) {
case add:
sp[1] += sp[0];
sp++;
break;
/* ... other instructions */
}
}
}
在螺紋解釋器,解碼代碼不集中,但在每一段代碼,處理指令的末尾處,而重複。這意味着一旦指令被解釋,而不是跳回到一些集中的解碼代碼,解釋器解碼下一條指令並立即跳轉到它。在ANSI-C中有效地實現線程代碼並不是真的可行,但GCC的「計算goto」擴展非常適合。這裏是以前解釋的線程版本:
void interpret() {
void* program[] = { &&l_add, /* ... */ };
int* sp = ...;
void** pc = program;
goto **pc; /* jump to first instruction */
l_add:
sp[1] += sp[0];
++sp;
goto **(++pc); /* jump to next instruction */
/* ... other instructions */
}
除了可節省跳躍,這種螺紋解釋也更有效,因爲複製的間接跳轉(下一條指令),可以預見通過現代的CPU更好。 Anton Ertl在his home page上發表了一些有趣的論文,特別是一篇名爲「高效翻譯的結構和性能」的文章,其中對上述代碼進行了修改。