【Firefox】SpiderMonkeyのコミッターになる方法【JavaScriptエンジン】

# はじめに

大学の実験でFirefoxのJavaScriptエンジン「SpiderMonkey」にコントリビュートする機会が得られたので、そのときに行った手順をまとめたいと思います。
これを読めばあなたもFirefoxのコミッターになることができます。

実験について詳しく知りたい方は[コチラ](http://snowman-mh.hatenablog.com/entry/2017/11/14/172328)をご覧ください。
また、この記事では、[実験のTAさんが作成してくれたスライド](https://doss.eidos.ic.i.u-tokyo.ac.jp/slides/04_js_workflow.pdf)を参考にして僕が行ったことをまとめています。

## 概要

大まかには以下の手順でSpiderMonkeyにコントリビュートしていきます。

1. ソースコードをダウンロードする
- `js shell`をビルドして動作確認する
- 仕様を満たすように変更を加える
- 既存機能を壊していないかテストする
- 変更内容をパッチ(変更内容のdiff)にする
- Bugzillaというバグトラッキングサイトにパッチを投稿する
- レビューもらって修正、マージ

# SpiderMonkeyにコントリビュートしよう

それではここからコントリビュートするための手順を解説していきます。
一応`macOS Sierra 10.12.6`の環境で行ったことなので、他の環境については[コチラ](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Simple_Firefox_build)を参考にやってみてください。

## ソースコードのダウンロード

環境構築用のスクリプトが用意されていて、それを起動して質問に答えていくだけで環境構築ができてしまいます。素晴らしいですね。
Pythonは2.7.11でなければならんと書いてありますが、僕は2.7.10でも問題ありませんでした。

```bash
$ mkdir src    # spider-monkeyとかいうディレクトリを作ってその中でやるといいと思います
$ cd src
$ wget https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py
$ python bootstrap.py
```

`src/`と同じ階層に`mozilla-unified/`というディレクトリが作成されていると成功です。

## ソースコードのビルド

ここでは、Firefox全体のビルドではなく、JavaScriptのシェルのみのビルドを行います。
`js shell`のみのビルドだと5分くらいで終わりますが、Firefox全体をビルドすると30分から数時間かかるそうです(やったことはない)。
JavaScriptエンジンに閉じた変更であれば`js shell`のみのビルドで十分です。

```bash
$ cd mozilla-unified/js/src
$ cp configure.in configure
$ chmod 0755 configure
$ mkdir build_DBG.OBJ
$ cd build_DBG.OBJ
$ ../configure --enable-debug --disable-optimize
$ make
```

これで`./dist/bin/`に`js`というバイナリができていると成功です。

## 動作確認

```bash
$ ./dist/bin/js
js> 1 + 2
3
js> [...!+[]+[]].reduce(_=>_+_,+{}+[])
"NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN"
```
## 変更を加える

ソースコードに変更を加えます。
といっても何を変更すれば良いかまったく分かりません。
ってか変更するところなんてあんの？って感じです。

### 変更するべき箇所の探し方

意外とあります。僕が知っているのは次の2つの方法です。

- [Bugzilla](https://bugzilla.mozilla.org/)というページに日々バグが報告されており、そこから解決できそうなものをピックアップする。
- [TC39という団体のGitHubリポジトリ](https://github.com/tc39/ecma262/blob/master/README.md)にはECMAScriptに追加する機能のプロポーザルがまとめられていて、ここから実装できそうな新機能を選ぶ。

僕の友人はプロポーザル一覧からパイプラインオペレーターを選んで実装していて、マージもされていました(すごい)。
その凄腕プログラマーたちのブログは[コチラ](http://siquare.hatenablog.com/entry/2017/10/25/151600)と[コチラ](http://hakatashi.hatenadiary.com/entry/implementing-pipeline-operator)です。

### エラーメッセージの改善

ここで、僕の行った変更を例として紹介します。
僕は「エラーメッセージを改善する」というテーマを選びました。
比較的小さな変更から大きめの変更まで様々なBugがあり、小さなタスクでコントリビュートを体験してみて、最後に大きめのタスクに挑戦できそうというモチベーションで選びました。
結果として、5行程度の変更、5行程度の変更、90行程度の変更という3つのIssueを解決することができました。
具体的にやったことは長くなるので別の記事にまとめました。
SpiderMonkeyのコードを読んでいく方法、デバッガを使って動作を追う方法なども書いています。

- [クラスを再宣言したときのエラーメッセージ](https://qiita.com/snowman_mh/items/e52202eee378e8481d3b)
- [`super();`を呼ばなかったときのエラーメッセージ](https://qiita.com/snowman_mh/items/e33f0b57e31f59acdc2d)
- [`in`演算子に関するエラーメッセージ](https://qiita.com/snowman_mh/items/f71029c1bb3b942295d1)

## 変更内容をパッチにする

変更した内容をパッチと呼ばれるファイルに出力します。
パッチとは、変更内容のdiffを分かりやすく記述したテキストファイルのことを言います。

### テストする

まず最初に、自分が変更したコードが既存の動作を壊していないかテストして確認する必要があります。
また、必要であれば自分の変更内容に関するテストも追加しましょう。

```bash
$ cd js/src/tests/
$ ./jstests.py ../build_DBG.OBJ/dist/bin/js ecma_6/Class/
```

最後の引数にはテストが置いてあるディレクトリを指定します。自分の変更内容にあったテストを指定しましょう(例えば、クラス宣言まわりを触ったのなら`ecma_6/Class/`など)。
ちなみにテストを指定しなければすべてのテストを実行するため、とても時間がかかります(やったことはない)。
`js shell`へのパスが違う場合は自分の環境に合うように変更してください。

### 変更したファイルを確認する

```bash
$ hg status .
```

`.`をつけなくてもOKですが実行に時間がかかります。
また、`.`をつけているため自分が今いるディレクトリ以下の変更内容しか出力してくれないことに注意してください(`js/src/`にいることを確認してください)。
いきなりでてきた`hg`コマンドですが、`git`みたいなもので、ソースコードをダウンロードしたときに使えるようになっているはずです。

### 変更内容を確認する

```bash
$ hg diff .
```

こちらも`.`をつけなくてもOKですが時間がかかります。

### 変更内容をコミットする

```bash
$ hg add .
$ hg commit -m "Bug [bug number] - [commit message]"
```

(例) `$ hg commit -m "Bug 123456 - Fix bug"`

最初の`add`ですが、`hg`には`git`と違ってStagingという概念がないので、新しいファイルを作成していなければ必要ありません。
`[bug number]`と`[commit message]`は適切なものに置き換えてください。
また、このコミットメッセージはBug fixの場合のフォーマットで、新機能の追加ならまた違うフォーマットを使う必要があるので、それは過去のコミットメッセージを見てみてください。


### 変更内容をパッチに出力する

```bash
$ hg export > ../bug[bug number].patch
```

`hg export`は標準出力に出すだけなので適宜ファイルにリダイレクトしてあげましょう。
特にパッチファイル名の規則はないらしいですが、`bug11111.patch`(`11111`は自分が担当したBugのbug number)とかにしておくとよいと思います。
また、パッチファイルは`hg`管理下に置きたくないので、`js/src/`より上に置いておくと良いでしょう。

## Bugzillaにパッチを投げる

こちらもBug fixの場合で、新機能の追加の場合は違うかもしれません。
作成したパッチをBugzillaに投げてレビューをもらいましょう。

1. 自分が担当しているBugzillaのバグページの`Attach File`をクリック
- さっき作ったパッチファイルを選択してDescriptionを書く(コミットメッセージと同じでOK)
- ContentTypeのFlagsのreviewを`?`にして、レビュアーを指定する(Assignしてくれた人にすると良いと思います)
- Commentに行った変更の内容を詳しめに書いてSubmit

## レビューを受けて修正する

レビューで問題があったら修正しましょう。もちろんなかったら修正の必要はないのでここは飛ばしてください。
1行は99文字以内であるとか、関数の`{}`はそれぞれ独立した行に書くとか、SpiderMonkeyのコード規約がいろいろあるので、その辺の指摘もあると思います。

1. 今まで通りコードを修正してビルド、仕様を満たしていて、テストが通るか確認する
- 次のコマンドでコミットを修正

    ```
    $ hg commit --amend
    ```
- コミットメッセージの変更を求められるが、変更せずに保存してエディタを終了すればOK
- 上記と同様にパッチファイルを作ってもう一度Bugzillaに投げる
  - そのときに過去のパッチを削除できるので削除しておく(下の方のチェックマークにチェックを入れる)

## try-runが終了するのを待つ

レビューされてAcceptされると、レビュワーの人がtry-runというCIのようなものを走らせてくれます。

- try-runが終了するの待つ(長いと3時間くらい、短いと30分くらい)
- テストが落ちずに終了したら、Bugzillaのバグページ上部にある`Edit Bug`を押す
  - optが付いているテストは予備のテストで、本体と予備のどちらかでパスしていたら気にしなくて良い
  - もちろんテストが落ちたら原因を究明して解決し、再度パッチを投げる必要があります。
- keyword欄に`checkin-needed`を追加して保存する
- 取り込まれるのを待つ

# おわりに

最後に[こんな感じ](https://hg.mozilla.org/mozilla-central/rev/389bd78cf79d)のコミットページのリンクがBugzillaのBugページにコメントされます。
ここにAuthorとして自分の名前が乗るのは感動的ですね。

これであなたもSpiderMonkeyのコミッターだ！！！