2013年9月22日日曜日

ESウェブブラウザ通信 - escudo 0.4シリーズ

ESウェブブラウザは先週CSS メディアクエリ レベル3に対応したescudo 0.3.3をリリースしたところ(*)ですが、今回はGitHubのescudoのレポジトリで開発中のescudo 0.4シリーズのお話です。

(*) メディアクエリの実装のお話はGoogle+のESウェブブラウザのコミュニティに載せてあるのでそちらも参照して下さい。

0.4シリーズはshared_ptrベースのpimplへ


今回マイナーバージョンをひとつ上げることになったのは、escudo内部のC++のObjectクラスの実装を変更したためです。このObjectクラスは、DOMのNodeをはじめWeb IDLのインターフェイスで定義されているすべてのインターフェイスのC++側の実装クラスの基底クラスになっているものです。

Objectとクラス階層

escudo 0.3シリーズの実装では、pimplイディオムを使って、オブジェクトの実体はObjectImpクラスを基底にした別クラスで実装するようになっています。またオブジェクトの寿命は、その中のcountという参照カウンタで管理しています。参照数の管理自体はObjectクラスがスマートポインタのようになっていて、なるべく自動で管理できるようにしていました。

escudo 0.3の実装
上図の説明: JS(SpiderMonkey)やV8がブリッジ経由でアクセスするのが外側のクラスで、その.cppや.hファイルはWebIDLの定義からesidlコンパイラがすべて自動で生成しています。実装側もそのスケルトンとなる.cppや.hはesidlで生成することができるので、『pimplイディオムって、地味に面倒』、"More work for the implementor. "と言われているpimplイディオムを適用するのがescudoではかなり簡単だったりしています。idlコンパイラを作ったり、WebIDLを書いたりするのが面倒なんじゃ…という説もありますが(笑)。(単純に外側が.hで実装側が.cppではない理由は以前にこのブログでまとめてあります。)

ただこの実装では、
  • 参照カウンタそのもののretain_, release_といったメンバ関数はObjectImp内に独自に記述している(マルチスレッドとかを考えると意外と大変)、
  • Object経由のアクセスは必ずしも速くないのでObjectImpの生ポインタを使っている箇所がかなりある(いまのC++で生ポインタはそんなに使うものではない)、
といった具合で安全に作っていくことが難しい面がありました。

そこでescudo 0.4シリーズでは実装側のオブジェクトの寿命をstd::shared_ptrで管理するようにObjectクラスを設計し直しました(shared_ptrを応用する方法の概略はboostのページで説明されています。)。shared_ptr以外の手法もあると思いますが、もし今後shared_ptr以外の手法を使いたくなったとしても、0.3シリーズのように実装側内部で参照カウンタを持っていてはやっぱり大変、ということもありました。

shared_ptrベースのpimpl (escudo 0.4)
この変更で0.4シリーズのソースコードは、
  • 参照数の管理はshared_ptrに任せる、
  • 生ポインタのかわりに関数の引数などは const shared_ptr<T>& を使う、
  • newのかわりに make_shared<T> を使う、
  • etc.、
といった具合に変わっています。0.3から0.4への修正は単純な置換で対応できる部分も少なくなかったのですが、その分量が、
299 files changed, 4073 insertions(+), 3577 deletions(-)
と結構な分量で、C++側のコードの互換性もなくなっていることからマイナー番号をひとつ上げることにしました。

この変更にあたっては、shared_ptrベースになったことで、実装側のクラスのコンストラクタ内部ではshared_from_this関数 (Impクラスのselfメンバ関数)が使えないといった制限が入り、コンストラクタ内部で従来のコードをそのまま実行することができない場面がありました。コンストラクタ本体が単純になること自体は悪いことではないので、これは結果オーライな感じもありますが注意点のひとつです(これにはまると、bad_weak_ptr例外と格闘することになります)。

まとめ


今回は1つの大きなチェンジリストでいきなりescudo(とesidl)のマイナーバージョンが上がっているので、その内容についてまとめました。GitHubのレポジトリの0.4は現状でもひとまず動作していますが、ここからリグレッションや循環参照の問題などを修正しつつ、0.4.0としてリリースする予定です。