threaded-code介绍
esxgx
threaded-code是通过把一系列调用指令转换成一完整的地址表,然后使用恰当的方式呼叫,最初用来减少代码的占用空间,提高代码密度的一种技术(Don't repeat yourself或DRY)。
可以看出,VM指令变得很多时,"case"也会变得很多, 最后的case对应的指令要执行会付出很多 比较/跳转 的额外代价。
esxgx
threaded-code是通过把一系列调用指令转换成一完整的地址表,然后使用恰当的方式呼叫,最初用来减少代码的占用空间,提高代码密度的一种技术(Don't repeat yourself或DRY)。
此技术目前不仅用于压缩代码,很多VM解释器用它来加快VM指令的执行速度(相对于switch-based dispatch)。
首先看典型的switch-based instruction dispatch实现VM指令分发:
typedef enum {
add /* ... */
} Inst;
void engine()
{
static Inst program[] = { add /* ... */ };
Inst *ip = program;
int *sp;
for (;;) {
switch (*ip++) {
case add:
sp[1]=sp[0]+sp[1];
sp++;
break;
/* ... */
}
/* ... */
}
可以看出,VM指令变得很多时,"case"也会变得很多, 最后的case对应的指令要执行会付出很多 比较/跳转 的额外代价。
而DTC采用了一种类似C中"函数指针数组"的思想(当然实际实现VM解释器时不难想到这一优化手段), 存储handler的地址, 然后用VM码作为handler的索引,例如下列伪代码就展示了DTC技术:
start:
ip = &thread
jump *ip++
thread:
&pushA
&pushB
&add
...
pushA:
*sp++ = A
jump *ip++
pushB:
*sp++ = B
jump *ip++
add:
*sp++ = *--sp + *--sp
jump *ip++
不幸的是, ANSI-C并没有提供"labels as values"的技术, 我们不能直接goto一个由label组成的数组。
幸运的是,不少C编译器扩展出这个功能(例如GCC), 因此我们就能这样写:
void engine()
{
static Inst program[] = { &&add /* ... */ };
Inst *ip = program;
int *sp;
goto *ip++; /* dispatch first VM inst. */
add: sp[1]=sp[0]+sp[1];
sp++;
goto *ip++; /* dispatch next VM inst. */
/* ... */
}
据"The Structure and Performance of Effcient Interpreters"中的实验, DTC 2倍于典型的switch-based instruction dispatch, 因此此技术能大幅提高VM的速率,减少VM执行的额外开销。