Deno に"守り"のコントリビュートしていたら、TC39 に出した言語仕様変更が承認され、ついでに V8 にパッチを投げた話
“守り”のコントリビュート
Deno が提供している API は多くが JavaScript で実装されています。もしプロトタイプ汚染に耐性のない JavaScript コードで API を実装してしまっていた場合、ネイティブのプロトタイプメソッドが変更されてしまったときに影響を受けてしまいます。
私はプロトタイプ汚染などによって想定外の動作を起こさせないように、Deno の内部コードに対して“守り”のコントリビュートをしてきました。
前回記事の RegExp を受け取る String のメソッドに進展があったのでアドベントカレンダーの記事として報告しようと思います。
文字列のメソッド仕様に Normative Change を出した
文字列のメソッドには String.prototype.split のように引数に文字列もしくは RegExp オブジェクトのいずれかを受け取るものがあります。
"a b c".split(" "); // ["a", "b", "c"]
"a b c".split(/\s/u); // ["a", "b", "c"]
仕様でメソッドに文字列か RegExp オブジェクトかのどちらが渡ってきたかを Symbol.split メソッドを持っているかどうかで判定していました。つまり String.prototype を汚染して Symbol.split メソッドを追加し、RegExp オブジェクトがを渡したときと同じ実行パスにすることで、結果を好き勝手にいじることができることを意味しています。
String.prototype[Symbol.split] = () => ["foo"];
"a b c".split(" "); // ["foo"]
これは Deno の問題というよりかは言語仕様の問題だと思ったので、ECMA-262 に Normative Change のプルリクエストを出しました。実装に影響のある変更は TC39 のメンバーに進めてもらう必要があったため Deno Land Inc. に所属している Luca さんにお願いし、実装のために必要な test262 のテストスイートを用意してもらい、会議の議題に出してもらいました。無事2025年2月の会議で承認してもらえました。
この Normative Change についての詳細は、ECMAScript Normative Changes Advent Calendar 2024 で書いた記事を参考にしてください。
V8 にパッチを投げた
Normative Change の承認が得られたため、2つのエンジンに実装されて問題ないことが確認されれば ECMA-262 に取り込まれます。JavaScriptCore (WebKit) に対しては Sosuke Suzuki さんが実装してくれましたが、V8 に対しては誰もイシュートラッカーすら用意していない状況でした。
このまま言語仕様に取り込まれないのは嫌だったため、自分で V8 にパッチを投げることにしました。タイムリーに Riya Amemiya さんが V8 にパッチを投げる手引きを書かれていたため、参考にさせてもらいました。
変更内容としては該当の String メソッド内で引数がオブジェクトかどうかをチェックするだけなので、C++ に少々苦戦しましたが実装できました。
何度かレビューしてもらいコードを修正し Chrome 143(V8 14.3.106)でシップされました。そして言語仕様の方も2025年12月10日にマージされました。
終わりに
今回は JavaScript の言語仕様に貢献した話でしたが、JavaScript に限らず Web 仕様の多くが当事者意識を持った貢献者によって成り立っていることを再確認しました。
何かブラウザやランタイムに問題があったときには、SNS で不満を言うだけになるのではなく、適切な場所に報告をし、必要があれば Web 仕様の変更、実装の修正を手伝い、みなさんも Web をより良いものにしていきましょう!
Discussion