8

私は非侵襲的な保守的な GC を C で書いていますが、そのスタック スキャン フェーズの正確性について懸念があります。

具体的には、コンパイラの最適化が有効になっていない場合、すべてのローカル変数 (オブジェクトを指す) が「予測どおりに」スタックに割り当てられるため、正常に動作します。では-O3、GC はいくつかの有効な参照を見逃しています。これは、コンパイラが一部の変数と関数引数の受け渡しに (GC がスキャンするスタックの代わりに) レジスタを使用することを選択し、GC が (まだ) それを処理するようにプログラムされています。(これがまだ起こるべきではなく、私が問題の原因を誤解していると思われる場合は、お知らせください。)

いくつかの基本的な要件 ( GC オブジェクトのGC_malloc代わりにa を使用する必要があるmallocこと、非 GC ヒープから GC ヒープを指さないようにすること、そしてもちろん、明示的に を呼び出さないことfree) を除けば、GC はクライアントからこれ以上の要件を持つべきではありません。コードまたはコンパイラ。したがって、クライアント コードから特別なパターンを追加する必要はありません。同様に、この GC を使用するプログラムを特別なコンパイラ フラグ (スタックの最適化を抑制する) で強制的にコンパイルすることは、せいぜい最後の手段です。これらの 2 つが邪魔にならないので、これが私の質問への積み上げです。

私は、GC が-O3(スタックの最適化を使用して) ケースをシームレスに処理できるようにする方法を見つけようとしています。これが私の一連の考えです(より正確には仮定):

  1. GCC (または有効なコンパイラ) がどこまで最適化を行っても、プログラムの正確性が損なわれることはありません。
  2. [1] が成り立つ場合、(少なくとも C の実際の実装では)到達可能な (任意の呼び出しレベルでローカルとして割り当てられた)変数がアクセス可能なままである場合、それはスタック上または現在のレジスタセットですが、実際には他のどこにもありません。
  3. [2] が成り立つ場合、GC サイクルの開始時にすべてのレジスタをスタックにダンプするだけで、その後のスタック スキャンで以前に見逃していた参照も検出されることが保証されます
  4. さらに、[1] と [2] が成り立つ場合、コンパイラーが変数の上書きを許可する場合 (ほとんどの場合、レジスターベースの変数の場合)、それは何らかのレベルのコード分析が実行され、それが証明されたことを意味します。その変数は、その関数の他の場所では使用されていません。したがって、その意味で、スタックまたはレジスタ ダンプに変数が表示されない場合、(理論的には) まだスコープ内にあるにもかかわらず、これは (私にとって) 警告の原因にはなりません。死んだ参照を取り除くことで、GC を助けただけです。

質問 #1: 4 つの仮定はすべて正しいですか?

質問 #2:レジスタ ダンプを強制する最も移植性の高い方法は何ですか? 単純なsetjmp呼び出しでこの効果が得られると主張する情報源をいくつか見つけました。これは正しいです?

4

2 に答える 2

1

Q1。はい、私はあなたの4つのステートメントすべてが当てはまると信じています(少なくともコンパイラのバグを無視した場合!)

Q2。setjmpは一部のレジスタを保存しますが、必ずしもすべてのレジスタを保存するわけではありません。ただし、setjmpによって保存されていないレジスタは、とにかくスタックに保存して保存する必要があるため、目的には十分です。

誰かがアドレスのように見えるものをどこかのバッファに保存していれば、そうでなくても、あなたのスキームはうまくいかないかもしれません。

また、ポインタを使って「面白い」ことをする人もいることを覚えておく必要があります。例えば

struct blah
{
    size_t size;
    char *file;
    int line;
};


struct blah *p = malloc(sizeof(struct blah) + size); 
... more lines of code goes here to fll in size, file and line in blah. 
void *np = (p+1); 

これは、保存されているポインタがブロックの先頭をまったく指していないことを意味します。

于 2013-01-24T23:44:25.713 に答える
1

#1の大きな問題は、未定義(または疑わしい)なことを実行するプログラムですが、一般的には機能します。ファイルに保存されたり、ネットワーク接続を介して送信されたり、通常はローカルで忘れられたりする魔法の定数としてポインターを使用するようなものですが、その後(ファイルまたはネットワークから)戻ってきて、後で参照解除される可能性があります。または、ノードごとにオーバーヘッドのポインターが1つしかないリンクリストの古い「xorprevandnextpointers」トリック。

于 2013-01-25T05:25:13.200 に答える