* template/yarvarch.ja:

Change encoding from Shift-JIS to UTF-8


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@33230 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ayumin 2011-09-08 17:09:30 +00:00
parent b81c4967f7
commit fa5446f14e
2 changed files with 207 additions and 202 deletions

View File

@ -1,4 +1,9 @@
Thu Sep 9 01:14:00 2011 Ayumu, AIZAWA <ayumu.aizawa@gmail.com> Fri Sep 9 02:02:09 2011 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
* template/yarvarch.ja:
Change encoding from Shift-JIS to UTF-8
Thu Sep 9 01:14:00 2011 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
* sample/drb/README.rd.ja: * sample/drb/README.rd.ja:
* sample/drb/dhasenc.rb: * sample/drb/dhasenc.rb:

View File

@ -1,17 +1,17 @@
#title YARVアーキテクチャ #title YARVアーキテクチャ
#set author 日本 Ruby の会 ささだこういち #set author 日本 Ruby の会 ささだこういち
- 2005-03-03(Thu) 00:31:12 +0900 いろいろと書き直し - 2005-03-03(Thu) 00:31:12 +0900 いろいろと書き直し
---- ----
* これは? * これは?
[[YARV: Yet Another RubyVM|http://www.atdot.net/yarv]] の 設計メモです。 [[YARV: Yet Another RubyVM|http://www.atdot.net/yarv]] の 設計メモです。
YARV は、Ruby プログラムのための次の機能を提供します。 YARV は、Ruby プログラムのための次の機能を提供します。
- Compiler - Compiler
- VM Generator - VM Generator
@ -22,72 +22,72 @@ YARV
- (experimental) AOT Compiler - (experimental) AOT Compiler
現在の YARV は Ruby インタプリタの拡張ライブラリとして実装しています。こ 現在の YARV は Ruby インタプリタの拡張ライブラリとして実装しています。こ
れにより、Ruby インタプリタの必要な機能(パーサ、オブジェクト管理、既存 れにより、Ruby インタプリタの必要な機能(パーサ、オブジェクト管理、既存
の拡張ライブラリ)などがほぼそのまま利用できます。 の拡張ライブラリ)などがほぼそのまま利用できます。
ただし、いくつかのパッチを Ruby インタプリタに当てなければなりません。 ただし、いくつかのパッチを Ruby インタプリタに当てなければなりません。
今後は、Ruby 本体のインタプリタ部分eval.cを置き換えることを目指して 今後は、Ruby 本体のインタプリタ部分eval.cを置き換えることを目指して
開発を継続する予定です。 開発を継続する予定です。
* Compiler (compile.h, compile.c) * Compiler (compile.h, compile.c)
コンパイラは、Ruby インタプリタのパーサによって生成された構文木RNode コンパイラは、Ruby インタプリタのパーサによって生成された構文木RNode
データによる木)を YARV 命令列に変換します。YARV 命令については後述しま データによる木)を YARV 命令列に変換します。YARV 命令については後述しま
す。 す。
とくに難しいことはしていませんが、スコープなどの開始時にローカル変数の初 とくに難しいことはしていませんが、スコープなどの開始時にローカル変数の初
期化などを行い、あとは構文木を辿り変換していきます。 期化などを行い、あとは構文木を辿り変換していきます。
変換中は Ruby の Array オブジェクトに YARV 命令オブジェクト、およびオペ 変換中は Ruby の Array オブジェクトに YARV 命令オブジェクト、およびオペ
ランドを格納していき、最後に実行できる形に変換します。コンパイラでは、コ ランドを格納していき、最後に実行できる形に変換します。コンパイラでは、コ
ンパイル中に生成するメモリ領域の管理が問題になることがありますが、YARV ンパイル中に生成するメモリ領域の管理が問題になることがありますが、YARV
の場合、Ruby インタプリタがすべて面倒をみてくれるのでこの部分は非常に楽 の場合、Ruby インタプリタがすべて面倒をみてくれるのでこの部分は非常に楽
に作ることができました(ガーベージコレクタによって自動的にメモリ管理をし に作ることができました(ガーベージコレクタによって自動的にメモリ管理をし
てくれるため)。 てくれるため)。
YARV 命令は、命令を示す識別子、オペランドなど、すべて 1 word (マシンで YARV 命令は、命令を示す識別子、オペランドなど、すべて 1 word (マシンで
表現できる自然な値。C 言語ではポインタのサイズ。Ruby インタプリタ用語で 表現できる自然な値。C 言語ではポインタのサイズ。Ruby インタプリタ用語で
は VALUE のサイズで表現されます。そのため、YARV 命令はいわゆる「バイト は VALUE のサイズで表現されます。そのため、YARV 命令はいわゆる「バイト
コード」ではありません。そのため、YARV の説明などでは「命令列」という用 コード」ではありません。そのため、YARV の説明などでは「命令列」という用
語を使っています。 語を使っています。
1 word であるため、メモリの利用効率は多少悪くなりますが、アクセス速度な 1 word であるため、メモリの利用効率は多少悪くなりますが、アクセス速度な
どを考慮すると、本方式が一番いいと考えております。たとえばオペランドをコ どを考慮すると、本方式が一番いいと考えております。たとえばオペランドをコ
ンスタントプールに格納し、インデックスのみをオペランドで示すことも可能で ンスタントプールに格納し、インデックスのみをオペランドで示すことも可能で
すが、間接アクセスになってしまうので性能に影響が出るため、却下しました。 すが、間接アクセスになってしまうので性能に影響が出るため、却下しました。
* VM Generator (rb/insns2vm.rb, insns.def) * VM Generator (rb/insns2vm.rb, insns.def)
rb/insns2vm.rb というスクリプトは、insns.def というファイルを読み込み、 rb/insns2vm.rb というスクリプトは、insns.def というファイルを読み込み、
VM のために必要なファイルを生成します。具体的には、命令を実行する部分を VM のために必要なファイルを生成します。具体的には、命令を実行する部分を
生成しますが、ほかにもコンパイルに必要な情報、最適化に必要な情報、やアセ 生成しますが、ほかにもコンパイルに必要な情報、最適化に必要な情報、やアセ
ンブラ、逆アセンブラに必要な情報を示すファイルも生成します。 ンブラ、逆アセンブラに必要な情報を示すファイルも生成します。
** 命令記述 ** 命令記述
insns.def には、各命令がどのような命令であるかを記述します。具体的には次 insns.def には、各命令がどのような命令であるかを記述します。具体的には次
の情報を記述します。 の情報を記述します。
- 命令の名前 - 命令の名前
- その命令のカテゴリ、コメント(英語、日本語) - その命令のカテゴリ、コメント(英語、日本語)
- オペランドの名前 - オペランドの名前
- その命令実行前にスタックからポップする値 - その命令実行前にスタックからポップする値
- その命令実行後にスタックにプッシュする値 - その命令実行後にスタックにプッシュする値
- その命令のロジックC 言語で記述) - その命令のロジックC 言語で記述)
たとえば、スタックに self をおく putself という命令は次のように記述しま たとえば、スタックに self をおく putself という命令は次のように記述しま
す。 す。
#code #code
/** /**
@c put @c put
@e put self. @e put self.
@j self を置く。 @j self を置く。
*/ */
DEFINE_INSN DEFINE_INSN
putself putself
@ -99,36 +99,36 @@ putself
} }
#end #end
この場合、オペランドと、スタックからポップする値は無いことになります。命 この場合、オペランドと、スタックからポップする値は無いことになります。命
令終了後、self をスタックトップに置きたいわけですが、それは val という、 令終了後、self をスタックトップに置きたいわけですが、それは val という、
スタックにプッシュする値として宣言しておいた変数に代入しておくことで、こ スタックにプッシュする値として宣言しておいた変数に代入しておくことで、こ
れを変換するとスタックトップに置く C プログラムが生成されます。 れを変換するとスタックトップに置く C プログラムが生成されます。
細かいフォーマットは insns.def の冒頭を参照してください。そんなに難しく 細かいフォーマットは insns.def の冒頭を参照してください。そんなに難しく
ないと思います。 ないと思います。
insnhelper.h というファイルに、命令ロジックを記述するために必要なマクロ insnhelper.h というファイルに、命令ロジックを記述するために必要なマクロ
が定義されています。また、VM の内部構造に関する定義は vm.h というファイ が定義されています。また、VM の内部構造に関する定義は vm.h というファイ
ルにあります。 ルにあります。
* VM (Virtual Machine, vm.h, vm.c) * VM (Virtual Machine, vm.h, vm.c)
VM は、実際にコンパイルした結果生成される YARV 命令列を実行します。まさ VM は、実際にコンパイルした結果生成される YARV 命令列を実行します。まさ
に、この部分が YARV のキモになり、将来的には eval.c をこの VM で置き換え に、この部分が YARV のキモになり、将来的には eval.c をこの VM で置き換え
たいと考えています。 たいと考えています。
現在の Ruby インタプリタで実行できるすべてのことが、この VM で実現できる 現在の Ruby インタプリタで実行できるすべてのことが、この VM で実現できる
ように作っています(現段階ではまだ完全ではありませんが、そうなるべきです)。 ように作っています(現段階ではまだ完全ではありませんが、そうなるべきです)。
VM は、単純なスタックマシンとして実装しています。スレッドひとつにスタッ VM は、単純なスタックマシンとして実装しています。スレッドひとつにスタッ
クひとつを保持します。スタックの領域はヒープから取得するので、柔軟な領域 クひとつを保持します。スタックの領域はヒープから取得するので、柔軟な領域
設定が可能です。 設定が可能です。
** レジスタ ** レジスタ
VM は 5 つの仮想的なレジスタによって制御されます。 VM は 5 つの仮想的なレジスタによって制御されます。
- PC (Program Counter) - PC (Program Counter)
- SP (Stack Pointer) - SP (Stack Pointer)
@ -136,77 +136,77 @@ VM
- LFP (Local Frame Pointer) - LFP (Local Frame Pointer)
- DFP (Dynamic Frame Pointer) - DFP (Dynamic Frame Pointer)
PC は現在実行中の命令列の位置を示します。SP はスタックトップの位置を示し PC は現在実行中の命令列の位置を示します。SP はスタックトップの位置を示し
ます。CFP、LFP、DFP はそれぞれフレームの情報を示します。詳細は後述します。 ます。CFP、LFP、DFP はそれぞれフレームの情報を示します。詳細は後述します。
** スタックフレーム ** スタックフレーム
obsolete (update soon) obsolete (update soon)
** フレームデザインについての補足 ** フレームデザインについての補足
Lisp の処理系などをかんがえると、わざわざブロックローカルフレームとメソ Lisp の処理系などをかんがえると、わざわざブロックローカルフレームとメソ
ッドローカルフレームのようなものを用意するのは奇異に見えるかもしれません。 ッドローカルフレームのようなものを用意するのは奇異に見えるかもしれません。
あるフレームを、入れ子構造にして、ローカル変数のアクセスはその入れ子を外 あるフレームを、入れ子構造にして、ローカル変数のアクセスはその入れ子を外
側に辿れば必ずたどり着くことができるからですつまり、lfp は必要ない)。 側に辿れば必ずたどり着くことができるからですつまり、lfp は必要ない)。
しかし、Ruby ではいくつか状況が違います。まず、メソッドローカルな情報が しかし、Ruby ではいくつか状況が違います。まず、メソッドローカルな情報が
あること、具体的にはブロックとselfcallee からみると recieverです。こ あること、具体的にはブロックとselfcallee からみると recieverです。こ
の情報をそれぞれのフレームにもたせるのは無駄です。 の情報をそれぞれのフレームにもたせるのは無駄です。
また、Ruby2.0 からはブロックローカル変数はなくなります(ブロックローカル また、Ruby2.0 からはブロックローカル変数はなくなります(ブロックローカル
引数は残るので、構造自体はあまり変わりません)。そのため、メソッドローカ 引数は残るので、構造自体はあまり変わりません)。そのため、メソッドローカ
ル変数へのアクセスが頻発することが予想されます。 ル変数へのアクセスが頻発することが予想されます。
このとき、メソッドローカル変数へのアクセスのたびにフレーム(スコープ)の このとき、メソッドローカル変数へのアクセスのたびにフレーム(スコープ)の
リストをたどるのは無駄であると判断し、明示的にメソッドローカルスコープと リストをたどるのは無駄であると判断し、明示的にメソッドローカルスコープと
ブロックフレームを分離し、ブロックフレームからはメソッドローカルフレーム ブロックフレームを分離し、ブロックフレームからはメソッドローカルフレーム
が lfpレジスタによって容易にアクセスできるようにしました。 が lfpレジスタによって容易にアクセスできるようにしました。
** メソッド呼び出しについて ** メソッド呼び出しについて
メソッド呼び出しは、YARV 命令列で記述されたメソッドか、C で記述されたメ メソッド呼び出しは、YARV 命令列で記述されたメソッドか、C で記述されたメ
ソッドかによってディスパッチ手法が変わります。 ソッドかによってディスパッチ手法が変わります。
YARV 命令列であった場合、上述したスタックフレームを作成して命令を継続し YARV 命令列であった場合、上述したスタックフレームを作成して命令を継続し
ます。とくに VM の関数を再帰呼び出すすることは行ないません。 ます。とくに VM の関数を再帰呼び出すすることは行ないません。
C で記述されたメソッドだった場合、単純にその関数を呼び出します(ただし、 C で記述されたメソッドだった場合、単純にその関数を呼び出します(ただし、
バックトレースを正しく生成するためにメソッド呼び出しの情報を付加してから バックトレースを正しく生成するためにメソッド呼び出しの情報を付加してから
行ないます)。 行ないます)。
このため、VM 用スタックを別途用意したものの、プログラムによってはマシン このため、VM 用スタックを別途用意したものの、プログラムによってはマシン
スタックを使い切ってしまう可能性がありますC -> Ruby -> C -> ... という スタックを使い切ってしまう可能性がありますC -> Ruby -> C -> ... という
呼び出しが続いた場合)。これは、現在では避けられない仕様となっています。 呼び出しが続いた場合)。これは、現在では避けられない仕様となっています。
** 例外 ** 例外
例外は、Java の JVM と同様に例外テーブルを用意することで実現します。例外 例外は、Java の JVM と同様に例外テーブルを用意することで実現します。例外
が発生したら、当該フレームを、例外テーブルを検査します。そこで、例外が発 が発生したら、当該フレームを、例外テーブルを検査します。そこで、例外が発
生したときの PC の値に合致するエントリがあった場合、そのエントリに従って 生したときの PC の値に合致するエントリがあった場合、そのエントリに従って
動作します。もしエントリが見つからなかった場合、スタックを撒き戻してまた 動作します。もしエントリが見つからなかった場合、スタックを撒き戻してまた
同様にそのスコープの例外テーブルを検査します。 同様にそのスコープの例外テーブルを検査します。
また、break、returnブロック中、retry なども同様の仕組みで実現します。 また、break、returnブロック中、retry なども同様の仕組みで実現します。
*** 例外テーブル *** 例外テーブル
例外テーブルエントリは具体的には次の情報が格納されています。 例外テーブルエントリは具体的には次の情報が格納されています。
- 対象とする PC の範囲 - 対象とする PC の範囲
- 対象とする例外の種類 - 対象とする例外の種類
- もし対象となったときにジャンプする先(種類による) - もし対象となったときにジャンプする先(種類による)
- もし対象となったときに起動するブロックの iseq - もし対象となったときに起動するブロックの iseq
*** rescue *** rescue
rescue 節はブロックとして実現しています。$! の値を唯一の引数として持ちま rescue 節はブロックとして実現しています。$! の値を唯一の引数として持ちま
す。 す。
#code #code
begin begin
@ -216,7 +216,7 @@ rescue C
end end
#end #end
は、次のような Ruby スクリプトに変換されます。 は、次のような Ruby スクリプトに変換されます。
#code #code
{|err| {|err|
@ -225,7 +225,7 @@ end
when B === err when B === err
when C === err when C === err
else else
raise # yarv の命令では throw raise # yarv の命令では throw
end end
} }
#end #end
@ -233,32 +233,32 @@ end
*** ensure *** ensure
正常系例外が発生しなかった場合と異常系例外が発生したときなどの2 正常系例外が発生しなかった場合と異常系例外が発生したときなどの2
種類の命令列が生成されます。正常系では、ただの連続したコード領域としてコ 種類の命令列が生成されます。正常系では、ただの連続したコード領域としてコ
ンパイルされます。また、異常系ではブロックとして実装します。最後は必ず ンパイルされます。また、異常系ではブロックとして実装します。最後は必ず
throw 命令で締めることになります。 throw 命令で締めることになります。
*** break, returnブロック中、retry *** break, returnブロック中、retry
break 文、ブロック中の return 文、retry 文は throw 命令としてコンパイル break 文、ブロック中の return 文、retry 文は throw 命令としてコンパイル
されます。どこまで戻るかは、break をフックする例外テーブルのエントリが判 されます。どこまで戻るかは、break をフックする例外テーブルのエントリが判
断します。 断します。
** 定数の検索 ** 定数の検索
定数という名前なのに、Ruby ではコンパイル時に決定しません。というか、い 定数という名前なのに、Ruby ではコンパイル時に決定しません。というか、い
つまでも再定義可能になっています。 つまでも再定義可能になっています。
定数アクセスのためのRuby記述は次のようになります。 定数アクセスのためのRuby記述は次のようになります。
#code #code
Ruby表現: Ruby表現:
expr::ID::...::ID expr::ID::...::ID
#end #end
これは、yarv命令セットでは次のようになります。 これは、yarv命令セットでは次のようになります。
#code #code
(expr) (expr)
@ -268,161 +268,161 @@ getconstant ID
#end #end
*** 定数検索パス *** 定数検索パス
もし expr が nil だった場合、定数検索パスに従って定数を検索します。この もし expr が nil だった場合、定数検索パスに従って定数を検索します。この
挙動は今後 Ruby 2.0 に向けて変更される場合があります。 挙動は今後 Ruby 2.0 に向けて変更される場合があります。
+ クラス、モジュールの動的ネスト関係(プログラムの字面上)をルートまで辿る + クラス、モジュールの動的ネスト関係(プログラムの字面上)をルートまで辿る
+ 継承関係をルートObjectまで辿る + 継承関係をルートObjectまで辿る
このため、クラス、モジュールの動的ネスト関係を保存しなければなりません。 このため、クラス、モジュールの動的ネスト関係を保存しなければなりません。
このために、thread_object には klass_nest_stack というものを用意しました。 このために、thread_object には klass_nest_stack というものを用意しました。
これは、現在のネストの情報を保存します。 これは、現在のネストの情報を保存します。
メソッド定義時、その現在のネスト情報をメソッド定義時にdupして加える メソッド定義時、その現在のネスト情報をメソッド定義時にdupして加える
ことで、そのメソッドの実行時、そのネスト情報を参照することが可能になりま ことで、そのメソッドの実行時、そのネスト情報を参照することが可能になりま
す。 す。
トップレベルでは、その情報はないことになります。 トップレベルでは、その情報はないことになります。
クラス/モジュール定義文実行時は、現在の情報そのものを参照することになり クラス/モジュール定義文実行時は、現在の情報そのものを参照することになり
ます。これは、クラススコープ突入時、その情報をクラス定義文にコピーします ます。これは、クラススコープ突入時、その情報をクラス定義文にコピーします
(すでにコピーされていれば、これを行いません)。 (すでにコピーされていれば、これを行いません)。
これにより、動的なネスト情報を統一的に扱うことができます。 これにより、動的なネスト情報を統一的に扱うことができます。
** 最適化手法 ** 最適化手法
YARV では高速化を目的としているので、さまざまな最適化手法を利用していま YARV では高速化を目的としているので、さまざまな最適化手法を利用していま
す。詳細は割愛しますが、以下に述べる最適化などを行なっております。 す。詳細は割愛しますが、以下に述べる最適化などを行なっております。
*** threaded code *** threaded code
GCC の C 言語拡張である値としてのラベルを利用して direct threaded code GCC の C 言語拡張である値としてのラベルを利用して direct threaded code
を実現しています。 を実現しています。
*** Peephole optimization *** Peephole optimization
いくつかの簡単な最適化をしています。 いくつかの簡単な最適化をしています。
*** inline method cache *** inline method cache
命令列の中にメソッド検索結果を埋め込みます。 命令列の中にメソッド検索結果を埋め込みます。
*** inline constant cache *** inline constant cache
命令列の中に定数検索結果を埋め込みます。 命令列の中に定数検索結果を埋め込みます。
*** ブロックと Proc オブジェクトの分離 *** ブロックと Proc オブジェクトの分離
ブロック付きメソッド呼び出しが行なわれたときにはすぐにはブロックを Proc ブロック付きメソッド呼び出しが行なわれたときにはすぐにはブロックを Proc
オブジェクトとして生成しません。これにより、必要ない Proc オブジェクトの オブジェクトとして生成しません。これにより、必要ない Proc オブジェクトの
生成を抑えています。 生成を抑えています。
Proc メソッドは、実際に必要になった時点で作られ、そのときに環境(スコー Proc メソッドは、実際に必要になった時点で作られ、そのときに環境(スコー
プ上に確保された変数など)をヒープに保存します。 プ上に確保された変数など)をヒープに保存します。
*** 特化命令 *** 特化命令
Fixnum 同士の加算などを正直に関数呼び出しによって行なうと、コストがかか Fixnum 同士の加算などを正直に関数呼び出しによって行なうと、コストがかか
るので、これらのプリミティブな操作を行なうためのメソッド呼び出しは専用命 るので、これらのプリミティブな操作を行なうためのメソッド呼び出しは専用命
令を用意しました。 令を用意しました。
*** 命令融合 *** 命令融合
複数の命令を 1 命令に変換します。融合命令は opt_insn_unif.def の記述によ 複数の命令を 1 命令に変換します。融合命令は opt_insn_unif.def の記述によ
り自動的に生成されます。 り自動的に生成されます。
*** オペランド融合 *** オペランド融合
複数のオペランドを含めた命令を生成します。融合命令は opt_operand.def の 複数のオペランドを含めた命令を生成します。融合命令は opt_operand.def の
記述によって自動的に生成されます。 記述によって自動的に生成されます。
*** stack caching *** stack caching
スタックトップを仮想レジスタに保持するようにします。現在は 2 個の仮想レ スタックトップを仮想レジスタに保持するようにします。現在は 2 個の仮想レ
ジスタを想定し、5状態のスタックキャッシングを行ないます。スタックキャッ ジスタを想定し、5状態のスタックキャッシングを行ないます。スタックキャッ
シングする命令は自動的に生成されます。 シングする命令は自動的に生成されます。
*** JIT Compile *** JIT Compile
機械語を切り貼りします。非常に実験的なコードものしか作っておりません。ほ 機械語を切り貼りします。非常に実験的なコードものしか作っておりません。ほ
とんどのプログラムは動きません。 とんどのプログラムは動きません。
*** AOT Compile *** AOT Compile
YARV 命令列を C 言語に変換します。まだ十分な最適化を行なえておりませんが、 YARV 命令列を C 言語に変換します。まだ十分な最適化を行なえておりませんが、
それなりに動きます。rb/aotc.rb がコンパイラです。 それなりに動きます。rb/aotc.rb がコンパイラです。
* Assembler (rb/yasm.rb) * Assembler (rb/yasm.rb)
YARV 命令列のアセンブラを用意しました。使い方は rb/yasm.rb を参照してく YARV 命令列のアセンブラを用意しました。使い方は rb/yasm.rb を参照してく
ださい(まだ、例示してある生成手法のすべてをサポートしているわけではあり ださい(まだ、例示してある生成手法のすべてをサポートしているわけではあり
ません)。 ません)。
* Dis-Assembler (disasm.c) * Dis-Assembler (disasm.c)
YARV 命令列を示すオブジェクト YARVCore::InstructionSequence には disasm YARV 命令列を示すオブジェクト YARVCore::InstructionSequence には disasm
メソッドがあります。これは、命令列を逆アセンブルした文字列を返します。 メソッドがあります。これは、命令列を逆アセンブルした文字列を返します。
* YARV 命令セット * YARV 命令セット
<%= d %> <%= d %>
* その他 * その他
** テスト ** テスト
test/test_* がテストケースです。一応、ミスなく動くはずです。逆にいうと、 test/test_* がテストケースです。一応、ミスなく動くはずです。逆にいうと、
このテストに記述されている例ではきちんと動作するということです。 このテストに記述されている例ではきちんと動作するということです。
** ベンチマーク ** ベンチマーク
benchmark/bm_* にベンチマークプログラムがおいてあります。 benchmark/bm_* にベンチマークプログラムがおいてあります。
** 今後の予定 ** 今後の予定
まだまだやらなければいけないこと、未実装部分がたくさんありますんでやって まだまだやらなければいけないこと、未実装部分がたくさんありますんでやって
いかなければなりません。一番大きな目標は eval.c を置き換えることでしょう いかなければなりません。一番大きな目標は eval.c を置き換えることでしょう
か。 か。
*** Verifier *** Verifier
YARV 命令列は、ミスがあっても動かしてしまうため危険である可能性がありま YARV 命令列は、ミスがあっても動かしてしまうため危険である可能性がありま
す。そのため、スタックの利用状態をきちんと事前に検証するようなベリファイ す。そのため、スタックの利用状態をきちんと事前に検証するようなベリファイ
アを用意しなければならないと考えています。 アを用意しなければならないと考えています。
*** Compiled File の構想 *** Compiled File の構想
Ruby プログラムをこの命令セットにシリアライズしたデータ構造をファイルに Ruby プログラムをこの命令セットにシリアライズしたデータ構造をファイルに
出力できるようにしたいと考えています。これを利用して一度コンパイルした命 出力できるようにしたいと考えています。これを利用して一度コンパイルした命
令列をファイルに保存しておけば、次回ロード時にはコンパイルの手間、コスト 令列をファイルに保存しておけば、次回ロード時にはコンパイルの手間、コスト
を省くことができます。 を省くことができます。
**** 全体構成 **** 全体構成
次のようなファイル構成を考えていますが、まだ未定です。 次のようなファイル構成を考えていますが、まだ未定です。
#code #code
u4 : 4 byte unsigned storage u4 : 4 byte unsigned storage
@ -450,5 +450,5 @@ CompiledFile{
} }
#end #end
Java classfile のパクリ。 Java classfile のパクリ。