解釈とスレッド解釈をデコードして派遣します
-
27-09-2019 - |
質問
私はプログラムの実行中に実際の違いを理解しようとしています 解釈とスレッドの解釈をデコードして派遣します.
両方の例は本当に役立ちます。
Java Bytecodeの仕組みと、アセンブリ言語の仕組みを理解しています。しかし、DDIとTIはどこに適合しますか?
コンテクスト: 仮想マシン:システムとプロセス用の汎用性の高いプラットフォーム
解決
(注:「デコードとディスパッチ」とは、スイッチベースのインタープリターを意味すると仮定します。)
実行時にスイッチベースとスレッドインタープリターの違いは、基本的に、実行されるジャンプの数です。
スイッチベースのインタープリターでは、命令は中央の場所でデコードされ、デコードの結果に基づいて、デコードされた命令を処理するコードの一部にジャンプが実行されます。そのコードが命令の解釈が完了したら、それは集中解除コードに戻り、次の命令が進みます。これは、(少なくとも)解釈された命令ごとに2つのジャンプが実行されることを意味します。次の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の「Computed 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にはいくつかの興味深い論文があります 彼のホームページ, 、特に「効率的な通訳者の構造とパフォーマンス」と呼ばれるもので、上記のコードが適応されました。