単純なVMを実装しており、現在、ランタイム演算を使用して、ベースポインターからのオフセットとして個々のプログラムオブジェクトアドレスを計算しています。
今日はこの件についていくつか質問をしましたが、どこにもゆっくりと進んでいないようです。
質問1からいくつかのことを学びました- オブジェクトと構造体のメンバーアクセスとアドレスオフセットの計算-最新のプロセッサには仮想アドレス指定機能があり、算術演算に専念する追加のサイクルなしでメモリオフセットを計算できることを学びました。
そして質問2から-アドレスオフセットはC/C ++のコンパイル時に解決されますか?-オフセットを手動で行う場合、これが発生する保証はないことを学びました。
ここまでで、私が達成したいのは、ハードウェアの仮想メモリアドレス指定機能を利用し、それらをランタイムからオフロードすることであることは明らかです。
プラットフォームに関してはGCCを使用しています-Windowsのx86で開発していますが、VMであるため、GCCでサポートされているすべてのプラットフォームで効率的に実行したいと考えています。
したがって、この主題に関する情報は歓迎され、非常に高く評価されます。
前もって感謝します!
編集:私のプログラムコード生成の概要-設計段階では、プログラムはツリー階層として構築され、オブジェクトにインデックスを付け、プログラムメモリブロックの先頭からのオフセットを計算するとともに、1つの連続したメモリブロックに再帰的にシリアル化されます。
編集2:VMの擬似コードは次のとおりです。
switch *instruction
case 1: call_fn1(*(instruction+1)); instruction += (1+sizeof(parameter1)); break;
case 2: call_fn2(*(instruction+1), *(instruction+1+sizeof(parameter1));
instruction += (1+sizeof(parameter1)+sizeof(parameter2); break;
case 3: instruction += *(instruction+1); break;
ケース1は、命令の直後にある1つのパラメーターを受け取る関数であるため、命令から1バイトのオフセットとして渡されます。命令ポインタは、次の命令を見つけるために1+最初のパラメータのサイズだけインクリメントされます。
ケース2は、前と同じように2つのパラメーターを受け取る関数で、最初のパラメーターは1バイトのオフセットとして渡され、2番目のパラメーターは1バイトのオフセットと最初のパラメーターのサイズとして渡されます。次に、命令ポインタは、命令のサイズと両方のパラメータのサイズによってインクリメントされます。
ケース3はgotoステートメントであり、命令ポインターはgoto命令の直後に続くオフセットによってインクリメントされます。
編集3:私の理解では、OSは各プロセスに専用の仮想メモリアドレス空間を提供します。もしそうなら、これは最初のアドレスが常に...よくゼロであることを意味します、それでメモリブロックの最初のバイトからのオフセットは実際にはこの要素のまさにアドレスです?メモリアドレスがすべてのプロセス専用であり、プログラムメモリブロックのオフセットとメモリブロックの最初のバイトからのすべてのプログラムオブジェクトのオフセットがわかっている場合、オブジェクトアドレスはコンパイル時に解決されますか?
問題は、これらのオフセットがCコードのコンパイル中に使用できないことです。これらのオフセットは、「コンパイル」フェーズおよびバイトコードへの変換中に認識されるようになります。これは、「無料」のオブジェクトメモリアドレス計算を行う方法がないことを意味しますか?
たとえば、仮想マシンのみがマシンコードにコンパイルされるJavaでこれはどのように行われるのでしょうか。これは、実行時の演算のために、オブジェクトアドレスの計算にパフォーマンスの低下が生じることを意味しますか?