Bug-org 1203381 IMEContentObserver should not post new notification after it posts some notifications but some of them are not performed yet
初回投稿日時: 2015年09月29日00時46分03秒
最終更新日時: 2015年09月29日00時48分02秒
カテゴリ: e10s IME Mozilla Core Mozilla43 バグ修正
SNS:
Tweet (list)
IMEContentObserver
のログを記録できるようにしてみたところ、異常な回数、NOTIFY_IME_OF_POSITION_CHANGE
を送信しているのを発見しました。もし無駄な呼び出しがあった場合、e10sモードではかなり無駄にCPUを走らせていることになります。
調べて見ると、nsRunnable
の派生クラスを利用して、script blockerが取り除かれた瞬間に何らかの通知を送信すると、特にe10sモードではContentCacheが必ず、WidgetQueryContentEvent
を発火してきます。これを処理するためにContentEventHandler
がペンディングとなっているレイアウトをフラッシュすることで、reflowが発生し、これがNOTIFY_IME_OF_POSITION_CHANGE
を送信の原因になっていることが多い事が分かりました。しかし、よく考えてみれば、何らかの通知を送信中に発生したreflowに対して、NOTIFY_IME_OF_POSITION_CHANGE
を送信する必要はないのです。なぜなら、そのreflowの結果から計算された情報をWidgetQueryContentEvent
で返すため、IMEからすると既に最新のレイアウト情報を持っているのに余分なNOTIFY_IME_OF_POSITION_CHANGE
を受け取ることになります。
これを解決するには通知を送信中に追加で発生した変更情報はマージし続けたり、不要なものは無視する必要があります。しかし、今までのIMEContentObserver
は各通知を個別のnsRunnable
の派生クラスに保存し、新しい通知が来た場合にはまだ前回の通知が処理されていなくても、再びnsRunnable
の派生クラスを生成していました。そのため、この複雑な状態を管理するためには多くのフラグを必要とします。しかし、そのようなコードでは限界が見えていますので大きく設計を変更することにしました。
まず、通知内容は全て実際に送信されるまでIMEContentObserver
自身が保持し続けるようにしました。これにより、nsRunnable
派生クラスを生成した後、実行までに新しい通知が発生しても、変更内容をマージするだけで済みます。
次に、nsRunnable
クラスを各通知ごとに生成するのではなく、通知を送信するクラスを一つにまとめ、これが実行された時に所定の順番で通知が行われるようになりました。これにより、通知の順番を常に保証することが可能になりました(テキストの変更範囲通知、選択位置の変更通知、レイアウトの変更通知の順でなくてはIMEから見た場合に矛盾が発生するため)。
最後に、順番の保証にも絡みますが、再帰呼び出しが発生していないか確認するようにし、再帰呼び出しになってしまう場合には実行予約だけをメインスレッドに投げるようにしました。これにより、スタックオーバーフローが発生する可能性も修正しています。