abcdefGets

ゲッツ!

FacebookのHermes Javascript Engineについて

最近、JSエンジンが何故かいくつか出て来たのでいっちょ見て見ることに
最初はFacebookが実装したjavascriptエンジンHermes(エルメス)の実装を見てみた

面倒くさいのでコードとかは引用しない

概要

どうやらReactNativeの高速化のために実装したエンジンのようだ
ReactNative側ですでに利用できるっぽい
売りとしてはバイトコードを出力・読み込みができるのでスタートアップタイムを高速化できるということらしい

commonjsの静的解析機能もついており今風な感じ

仕様

サポートされる仕様はhttps://github.com/facebook/hermes/blob/master/doc/Features.mdにある

サポートしている言語仕様はES5 + α

let/constやclass、ES Moduleといった機能はサポートされていない
とりあえずbabelとかts使うから動くでしょ といったところか

またReflectionwithSymbol.speciesといったものは今後もサポートしないらしい

Function.prototype.toStringソースコードを返さないなど、割と必要ないものはバッサリ切った感じ
React Navtiveのためと言っているのでいいのかな

ビルド

成果物が結構あるのに解説があんまないので困る

以下が成果物

中身

とりあえず概要をみてみた
以下が基本的なパスとなりそう

ソースコード => AST => IR => (最適化) => バイトコード => 実行

またバイトコードを読み込むことで

バイトコード => 実行

のパスもある

AST

NodeがあってBNF定義に近いASTがある
要は普通のAST実装
ただdecoratorで実装しているっぽいのでちょっと読みづらい

Visitorパターンでトラバーサルする

IR

ASTが生成されたらIRを生成する
hermesのIRはCFGも兼ねるグラフとなっている
このIRは結構低レベルでInstructionレベルまで表現している

バイトコード

IRから変換して生成される
OPコードは1byteでOperandは可変長

VM

バイトコードを実行するVMレジスタベースの仮想マシン
教科書通りGCC拡張のアドレスへのgotoとLabelアドレスの取得機能でループ無しで実装されている
ただしサポートされないコンパイラ向けにループとSwitch構文での実行機能も持っている

レジスタ

VMで利用されるレジスタは一応無限の仮想レジスタとなっているが、単純なリニア生存区間解析をCFG上で行っている
一応無制限と書いたのは、Bytecodeのレジスタインデックスが1byteしか受けつけないので、実質256までしかレジスタ割付ができないからである

https://github.com/facebook/hermes/blob/master/doc/Design.mdに書いてあるが、Facebook調べでは256以上のレジスタを使う関数は
見当たらなかったらしい(ので大丈夫ということか)

ABI

Facebook HermesはNaN-Boxingでオブジェクトを表現している

NaN-Boxingとは64bitフロートのNaN定義を利用したポインタと数値の表現方法
NaNは上位17bitが1であれば下位のBitがどんな値でも問題ないので、それを利用してポインタやタグ情報を埋め込んでいる
ただし64bitシステムだとポインタは64bit利用するので埋め込めないように見えるのだが、現状64bitシステムであっても全ての領域は使い切っていないので問題なく収まる (Linux x86-64で48bitまで利用と書いてあった)
ただし、そこまで考えなくてもVMのヒープが47bitで収めきればいいだけなので、そこまで問題は起きないだろう

Hidden Class

今のご時世、ShapeやらHidden Classは高速化に必須だろう
HermesもHidden Classを実装している
V8と同じようにオブジェクトレイアウトをclassとして認識して、プロパティの追加・削除等のレイアウト変更を行うと新たなクラスが生成されるようになっている

新たにHidden Classを生成した場合はtransitionをした結果を保存して検索するような仕組みになっている

IC

複雑なインラインキャッシングは実装されていないように見える
一応プロパティのキャッシュとhidden classの保持はしているのでプロパティキャッシュ自体はしているが

正規表現

正規表現は独自バイトコードを使ったVM型のエンジンを実装している
既存のエンジンのJITに比べるとちょっと見劣りするかもしれない

最適化

主にIRに対しての最適化が実行されている
内容はIRのloweringとかinline化など
面倒だったのであんまりちゃんと読んでない

JIT

実はJITエンジンももっている がまだリリースされていなのでOFFになっている
中を見た感じx86-64から提供する様だ

ARMは...?

まとめ

React Nativeのために作ったというだけあって、色々省いてあったりバイトコードローディングなど工夫があった
後発のエンジンなだけにcommonjs対応してたり、今風な感もあって面白い

ただ、言語仕様がEcmascriptのエディションと変わってきてしまっている(withがなかったり)のはちょっと気になっている

最近感じていることだが、Ecmascriptも仕様が大きくなってきていてエンジンの実装も大変になってきているし、
使用目的がはっきりしているエンジンにとっては多分サポートする意味の無い機能(withとかnot strictなモード、多言語対応等)は省いたEcmascriptのサブセットがあってもいいのかもしれない
というか個人的にはほしい

RegEx実装するだけでICU必要になったり面倒なことが多い