Bug-org 822866 Can't build using MSVC with enable-optimize=-O2 since landing of bug 813445
初回投稿日時: 2013-01-02 10:03:08
最終更新日時: 2013-01-02 10:04:13
カテゴリ: Mozilla Core Mozilla20 Windows バグ修正
SNS:
Tweet (list)
Bug-org 813445の修正で、VC++では-O2で最適化ビルドを作ろうとするとコンパイラがクラッシュするというregressionが出ました。もちろんVC++自体のバグなのですが、そうも言ってられません。
パフォーマンスを意識して、メンバを一括でmemcpy()を使ってOR演算や、初期化できるようにしていましたが、コンストラクタや、代入演算子を定義していたため、C++03では、非PODクラスということになるらしく、memcpy()が危険だという助言を、例によってえむけいさんから頂きました。ところが、PODクラスにしてもVC++のクラッシュは修正できませんでした。
そこで、クラッシュした行に着目してみると、以下のようなコードになっていました。
inline EventFlags operator|(const EventFlags& aOther) const
{
EventFlags flags;
flags.SetRawFlags(GetRawFlags() | aOther.GetRawFlags());
return flags;
}
クラッシュしたのは、SetRawFlagsの行です。ここで、それぞれのメソッドの実装は次のようになっています。
inline void SetRawFlags(RawFlags aRawFlags)
{
MOZ_STATIC_ASSERT(sizeof(EventFlags) <= sizeof(RawFlags),
"mozilla::widget::EventFlags must not be bigger than the RawFlags");
memcpy(this, &aRawFlags, sizeof(EventFlags));
}
inline RawFlags GetRawFlags() const
{
RawFlags result = 0;
memcpy(&result, this, sizeof(EventFlags));
return result;
}
試しに、これらのinline指定を削除してみると、コンパイラがクラッシュしなくなりました。ということで、バグはここの最適化にあるようです。
結果的には、operatorをUnion()というメソッドに変更し、一度、変数にGetRawFlags()から得た演算結果を保存してから、SetRawFlags()を呼び出すことで、コンパイラのバグを回避しています。
また、非PODクラスのままでは不安が残るので、EventFlagsをBaseEventFlagsと名前を変更し、コンストラクタを削除、上述の通り、|=演算子をUnion()というメソッドに置き換えました。
そして、コンストラクタが無いのは不便なので、新たにEventFlagsというコンストラクタだけを追加した派生クラスを用意し、Union()メソッドを使うような局面では、こちらをローカル変数として利用することで、Clear()メソッドをいちいち呼ばなくとも、自動で初期化されるように修正しています。