なぜzkEVMではレジスタマシンの実装が多いのか
EVMはスタックベースのVMであるが、ほとんどのzkEVM(Scroll VMはスタックベース)はレジスタベースで設計されている。 そもそも、コレらの違いと利点は何なのか
EVM以外の例としてJavaのJVMもスタックベース。レジスタベースだとあまり例が見つからないがLuaVMとかある
基本としてやってることは同じで以下の機能を網羅している
1. ソース言語のVM固有のバイトコードへのコンパイル
2. 命令とオペランドを含むデータ構造(命令が処理するデータ)
3. 関数呼び出し操作の呼び出しスタック
4. 実行する次の命令を指す「命令ポインタ」(IP)
5. 仮想「CPU」–命令ディスパッチャ
次の命令をフェッチ(命令ポインタによってアドレス指定される)
オペランドをデコード
命令を実行
スタックベース
https://scrapbox.io/files/62dfe56928d9ee001d3256c5.png
メリット
オブジェクトコードのコンパクトさ
コンパイラの単純さ
インタプリタの単純さ
プロセッサの状態数が少ない
高速なオペランドアクセス
デメリット
メモリ参照が多い
再利用が最適化されない
コード順序の厳密性
高速レジスタを隠蔽する
仮想スタックマシンの問題点
レジスタベース
https://scrapbox.io/files/62dfe570bf3ae2001d48ea63.png
メリット
スタックへのプッシュとスタックからのポップのオーバーヘッドが存在せず、レジスタベースのVM内の命令が命令ディスパッチループ内でより高速に実行される
スタックベースのアプローチでは実行できない最適化が可能になる
1つの例として、コードに共通のサブ式がある場合、レジスタモデルはそれを一度計算し、サブ式が再び表示されたときに将来使用するために結果をレジスタに格納できるため、式の再計算のコストが削減される
zk回路計算はコストも時間もかかるのでこのメリットを活かして最適化したり、lookup tableを使ったソリューションを組み込むことがzkEVM設計のキモ
デメリット
オペランドアドレスを明示的に指定する必要があるため、平均レジスタ命令が平均スタック命令よりも大きい
スタックポインタのためにスタックマシンの命令は短いのに対し、それぞれのレジスタマシンの命令にはオペランドの位置が含まれている必要があり、スタックコードに比べてレジスタコードが大きくなる
スタックマシンより構築が大変
コールスタックを実装する必要がある
命令はレジスタを利用するので密度が高い
直接レジスタを参照することができる
スタックマシンよりも少ない命令数でいい
その結果、パフォーマンスはあがる
順序依存性が低く、最適化の余地が広い
コンパイラを実装するのも大変
サイズが大きくなる傾向がある
zkEVMの誕生が騒がれていた理由はこの構築の大変さが大きい。また、Optimistic Rolllupが先に出てきたのもEVMベースでよかったから
参考文献