====== mruby命令セット ====== 対応risv:00090000 ===== OP_NOP (0x00) ===== OP_NOP --> No operation ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | | | | | | | | | | | | | | | | | 0000000 ||||||| 何もしない。 ===== OP_MOVE (0x01) ===== OP_MOVE A, B --> R(A) := R(B) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 0000001 ||||||| R(B)をR(A)にコピーする。コピー後のR(B)も残ったまま。 ===== OP_LOADL (0x02) ===== OP_LOADL A, Bx --> R(A) := Lit(Bx) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0000010 ||||||| Poolにあるリテラル値[Bx]をR(A)に代入する。 ===== OP_LOADI (0x03) ===== OP_LOADI A, sBx --> R(A) := sBx ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| sBx(+32767オフセットされた整数値) |||||||||||||||| 0000011 ||||||| R(A)に整数値(-32767~+32768)を代入する。 ===== OP_LOADSYM (0x04) ===== OP_LOADSYM A, Bx --> R(A) := Sym(Bx) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0000100 ||||||| R(A)にシンボルSym(Bx)を代入する。 ===== OP_LOADNIL (0x05) ===== OP_LOADNIL A --> R(A) := nil ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 0000101 ||||||| R(A)にnilを代入する。 ===== OP_LOADSELF (0x06) ===== OP_LOADSELF A --> R(A) := self ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 0000110 ||||||| R(A)にselfを代入する。selfはR(0)なので、OP_MOVE A,0と等価。 ===== OP_LOADT (0x07) ===== OP_LOADT A --> R(A) := true ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 0000111 ||||||| R(A)にtrueを代入する。 ===== OP_LOADF (0x08) ===== OP_LOADF A --> R(A) := false ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 0001000 ||||||| R(A)にfalseを代入する。 ===== OP_GETGLOBAL (0x09) ===== OP_GETGLOBAL A, Bx --> R(A) := getglobal(Sym(Bx)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0001001 ||||||| グローバル変数Sym(Bx)を取得し、R(A)に代入する。存在しない場合はnilを代入する。 ===== OP_SETGLOBAL (0x0a) ===== OP_SETGLOBAL A, Bx --> setglobal(Sym(Bx), R(A)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0001010 ||||||| グローバル変数Sym(Bx)にR(A)を代入する。(既にあれば上書き、なければ新規作成される) ===== OP_GETSPECIAL (0x0b) ===== OP_GETSPECIAL A, Bx --> R(A) := Special[Bx] ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0001011 ||||||| FIXME 現時点ではFixnumの0がR(A)に代入される。Bxは無視。 ===== OP_SETSPECIAL (0x0c) ===== OP_SETSPECIAL A, Bx --> Special[Bx] := R(A) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0001100 ||||||| 現時点では何もしない。FIXME ===== OP_GETIV (0x0d) ===== OP_GETIV A, Bx --> R(A) := ivget(Sym(Bx)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0001101 ||||||| R(0)つまりselfのインスタンス変数リストから、シンボルSym(Bx)に対応する値を取得してR(A)に代入する。selfがオブジェクトでない場合or見つからない場合はnilを代入する。 ===== OP_SETIV (0x0e) ===== OP_SETIV A, Bx --> ivset(Sym(Bx), R(A)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0001110 ||||||| R(0)つまりselfのインスタンス変数リストのシンボルSym(Bx)にR(A)を保存する。リストやシンボルが未生成の場合は作成する。 なお、selfがオブジェクトでは無い場合、ARGUMENT_ERRORでraiseする。 ===== OP_GETCV (0x0f) ===== OP_GETCV A, Bx --> R(A) := cvget(Sym(Bx)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0001111 ||||||| クラス変数Sym(Bx)を取得し、R(A)に代入する。変数が存在しない場合はNameError例外(uninitialized class variable)を発生する。 検索対象のクラスcはci->proc->target_class(NULLならばci->target_class)である。c->iv_tblから検索し、見つからなければ 上位(c->super)へと遡って検索する。 ===== OP_SETCV (0x10) ===== OP_SETCV A, Bx --> cvset(Sym(Bx), R(A)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0010000 ||||||| OP_GETCVと同じルールでクラスを遡り、クラス変数Sym(Bx)が存在すれば、その内容をR(A)で上書きする。なお、見つからなかった場合は、ci->target_class->iv_tblに新規登録する。 ===== OP_GETCONST (0x11) ===== OP_GETCONST A, Bx --> R(A) := constget(Sym(Bx)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0010001 ||||||| 定数Sym(Bx)を取得し、R(A)に代入する。以下の順序で検索し、最初に見つかった値が利用される。 - c=ci->proc->target_classが非NULLならば、ci->proc->target_class->iv - c=ci->target_classが非NULLならば、ci->target_class->iv - cのouterモジュール(内側から外側に向かって遡る) * outerモジュールは ivから__outer__を参照すると得られる。 - cと、そのsuperクラス(サブクラスからスーパークラスに向かって遡る) - (cがMODULEの場合のみ) Objectクラスのiv (Objectおよびそのsuperへ遡る) 見つからなかった場合、cからsuperに向かって遡りながら、const_missingというメソッドを検索する。メソッドが見つかった場合はそれを実行する。 メソッドが見つからなかった場合はNameError例外(uninitialized constant)を発生させる。 ===== OP_SETCONST (0x12) ===== OP_SETCONST A, Bx --> constset(Sym(Bx), R(A)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0010010 ||||||| 定数Sym(Bx)を定義する。ci->proc->target_classまたはci->target_classのivにSym(Bx)の名前でR(A)の内容を登録する。FIXME 二重登録時の警告は? ===== OP_GETMCNST (0x13) ===== OP_GETMCNST A, Bx --> R(A) := R(A)::Sym(Bx) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0010011 ||||||| R(A)が指すクラス(またはモジュール)レベルの定数Sym(Bx)を取得し、R(A)に代入する。なお、命令実行前のR(A)がクラス/モジュールでは無い((MRB_TT_CLASS,MRB_TT_MODULE,MRB_TT_SCLASSのいずれでもない))場合、TypeError例外(constant look-up for non class/module)を発生させる。定数検索のルールは、OP_GETCONSTの4,5と同じ。 ===== OP_SETMCNST (0x14) ===== OP_SETMCNST A, Bx --> R(A+1)::Sym(Bx) := R(A) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0010100 ||||||| R(A+1)の指すクラス/モジュールに属する定数Sym(Bx)を定義する。OP_GETMCNSTと同じ方法でR(A+1)がクラス/モジュールであることを確認し、インスタンス変数としてSym(Bx)=R(A)を登録する。 R(A+1)がクラス/モジュールでない場合は、OP_GETMCNSTと同じく例外を発生させる。 ===== OP_GETUPVAR (0x15) ===== OP_GETUPVAR A, B, C --> R(A) := uvget(B, C) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 0010101 ||||||| C段分上位のメソッド/ブロックの変数R(B)を取得し、現在のブロックのR(A)に代入する。\\ なお、C=0はci->proc->env、C=1はci->proc->env->c、C=2は( (REnv*)Ci->proc->env->c)->c、以下同様。対応するenvが存在しない場合はR(A)にnilを代入する。 ===== OP_SETUPVAR (0x16) ===== OP_SETUPVAR A, B, C --> uvset(B, C, R(A)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 0010110 ||||||| C段分上位のメソッド/ブロックの変数R(B)に、R(A)の内容を代入する。C段の遡り方はOP_GETUPVARに同じ。 対応するenvが存在しない場合は、何もしない。(エラーにもならない) ===== OP_JMP (0x17) ===== OP_JMP sBx --> pc += sBx ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | sBx(+32767オフセットされた整数値) |||||||||||||||| 0010111 ||||||| PCを変更し、現在のirep中でジャンプする。なお、変更前のPCはこのJMP命令がある場所そのものであり、PC++する前の値である。 また、JMP命令なのでPC++は実施されない。従って、-32767個前~JMP命令自身~+32768個後まで合計65536通りの場所にジャンプできる。 ===== OP_JMPIF (0x18) ===== OP_JMPIF A, sBx --> if R(A) pc += sBx ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| sBx(+32767オフセットされた整数値) |||||||||||||||| 0011000 ||||||| R(A)がfalseまたはnilのときは、ジャンプしない(つまりPC++)。それ以外の時はJMP命令と同様にジャンプする。 ===== OP_JMPNOT (0x19) ===== OP_JMPNOT A, sBx --> if !R(A) pc += sBx ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| sBx(+32767オフセットされた整数値) |||||||||||||||| 0011001 ||||||| R(A)がfalseまたはnilのとき、JMP命令と同様にジャンプする。それ以外の時はジャンプしない(つまりPC++)。 ===== OP_ONERR (0x1a) ===== OP_ONERR sBx --> rescue_push(pc + sBx) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | sBx(+32767オフセットされた整数値) |||||||||||||||| 0011010 ||||||| rescue節を登録する。登録先のmrb->rescueが未生成の場合、サイズ16で作成。mrb->rescueのサイズ(mrb->rsize)が足りない場合、自動的に2倍に拡張する。 登録はPC+sBxの計算結果をrescueの現在位置(0から昇順)に記録する。mrb->ci->ridxは**次の**rescue保存位置を指す。 ===== OP_RESCUE (0x1b) ===== OP_RESCUE A --> clear(exc); R(A) := exception (ignore when A=0) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 0011011 ||||||| R(A)に現在のRObject* mrb->excの内容を設定する。mrb->excはNULLに設定される。 ===== OP_POPERR (0x1c) ===== OP_POPERR A --> A.times { rescue_pop() } ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 0011100 ||||||| mrb->ci->ridxをAだけ減らす。ONERRで登録したrescue節を通らずに抜けるのに利用する。 ===== OP_RAISE (0x1d) ===== OP_RAISE A --> raise(R(A)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 0011101 ||||||| 例外を投げる。投げる例外オブジェクトはR(A)。なお、これは例外**オブジェクト**でなければならない。つまり、 NilClass,TrueClass,FalseClass,Fixnumといった型は渡せず、内部表現が mrb_value.value.p を用いる型しか渡せない(これは言語仕様でも規定されている)。 ===== OP_EPUSH (0x1e) ===== OP_EPUSH Bx --> ensure_push(SEQ[Bx]) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | Bx |||||||||||||||| 0011110 ||||||| ensure節を登録する。(irep->idx+Bx)番目のirepのクロージャを新規作成し、それをmrb->ensureに登録する。 mrb->ensureバッファはrescueバッファ同様に、未作成ならサイズ16で作成、個数オーバーなら2倍拡張となる。 mrb->ci->eidxは次の登録番号(つまり現在の登録個数)を指す。 ===== OP_EPOP (0x1f) ===== OP_EPOP A --> A.times { ensure_pop().call } ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 0011111 ||||||| ensureバッファの最後尾にあるクロージャをpopしてecallする作業をA回繰り返す。ensure付きのブロックを抜ける(つまりensure節が実行される)ときに利用する。 ===== OP_SEND (0x20) ===== (1) OP_SEND A, B, C (C=0) --> R(A) := call(R(A), mSym(B)) (3) OP_SEND A, B, C (0 R(A) := call(R(A), mSym(B), R(A+1), ..., R(A+C)) (2) OP_SEND A, B, C (C=127) --> R(A) := call(R(A), mSym(B), *R(A+1)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 0100000 ||||||| mSym(B)で指定された関数/メソッドを呼び出す。レシーバがR(A)、R(A+1)~R(A+C)が引数(C=0のときは無し)、 R(A+C+1)がブロック(SENDならnilを自動代入、SENDBならブロック)となる。ただしこれは引数が126個以下の場合で、 引数が127個以上の場合は、引数を収めたArrayをR(A+1)に、R(A+2)にブロックを格納し、C=127とする。 レシーバの型内でメソッド(シンボルmSym(B))の検索を行い、該当するものが存在しない場合は、method_missingというメソッドの 呼び出しにすり替えて実行する。すり替えを実施する場合、見つからなかったシンボルが第1引数となり、第2引数以降が元々の引数となる。 - callinfoバッファに1つpush。 * これから呼ぶメソッドのシンボルをci->mid、そのprocをci->proc、**現在の**スタックトップをci->stackidx、引数の個数((Array渡しのときは-1))をci->argc、レシーバのクラスをci->target_class、現在のpc+1をci->pc、A値をci->accにそれぞれ代入する。 - スタックをAずらす。つまり、呼び出し先のR'(0)が現在のR(A)となる。(だから、R(A)にレシーバを入れると丁度いいわけだ。) - 呼び出し自体は、呼び出し先の種類(C実装のfunction/Ruby実装のmethod)によって異なる。 * 呼び出し先がC実装関数(function)である場合 - 引数の個数((Array渡しの場合は1))+2をci->nregsに記憶 - mrbとレシーバを渡して該当関数を呼ぶ - スタック末尾(つまりR(A))に関数の戻り値を格納 - mrc->excが設定されていればOP_RAISE処理へジャンプ - レジスタ先頭位置、スタック位置をci->stackidxを用いて元に戻す。 - callinfoバッファから1つpopする。 * 呼び出し先がrubyのmethodである場合。 - 実行中proc、irep、pool、symsを呼び出し先メソッドの内容に変更する。 - irep->nregsをci->nregsに記憶 - スタックを拡張する * Array渡しの場合、[irep->nregs,3].max 個確保(room)し、そのうち3個をkeepする。 * レジスタ渡しの場合、irep->nregs個確保(room)し、そのうち(ci->argc+2)個をkeepする。 - レジスタ先頭位置をスタック末尾(つまりR(A)==R'(0))の位置にする。 - PCをirepの先頭にする。 ===== OP_SENDB (0x21) ===== (1) OP_SENDB A, B, C (C=0) --> R(A) := call(R(A), mSym(B), &R(A+1)) (3) OP_SENDB A, B, C (0 R(A) := call(R(A), mSym(B), R(A+1), ..., R(A+C), &R(A+C+1)) (2) OP_SENDB A, B, C (C=127) --> R(A) := call(R(A), mSym(B), *R(A+1), &R(A+2)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 0100001 ||||||| 説明は OP_SEND を参照。 ===== OP_FSEND (0x22) ===== 未実装。現時点ではNOPと同じ。 ===== OP_CALL (0x23) ===== OP_CALL --> self.call(frame.argc, frame.argv) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | | | | | | | | | | | | | | | | | 0100011 ||||||| Proc#callの実装用命令。codegenで生成されることはなく、Proc#call(またはProc#[])の内部実装のみに使われている。 これの命令が実行された場合、selfつまりR(0)はProcのインスタンスを指しており、それが保持しているクロージャmへのcallにすり替える作業を行う。 * ci->target_classにm->target_classを上書き * ci->procにmを上書き * (m->envが存在すれば) ci->midにm->env->midを上書き * (m->envが存在し、m->env->stackが存在しなければ) m->env->stackにmrb->stackを代入 * あとはSENDと同じ。 ===== OP_SUPER (0x24) ===== OP_SUPER A, C --> R(A) := super(R(A+1), ..., R(A+C+1)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | C ||||||| 0100100 ||||||| self(==R(0))をレシーバとし、ci->target_class->superからci->midのシンボルを探して実行する。 呼び出し本体の挙動はSENDと同じ。 ===== OP_ARGARY (0x25) ===== FIXME ===== OP_ENTER (0x26) ===== OP_ENTER Ax --> argument setup (m1:o:r:m2:k:kd:b) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | Ax ||||||||||||||||||||||||| 0100110 ||||||| | | | m1 ||||| o ||||| r | m2 ||||| k ||||| kd | b |:::||||||| メソッドやブロックの先頭で用いられ、スタックに積まれた引数を使用できるようにする命令。 各パラメータの意味は以下の通り。 * m1 : 引数(省略不可)の個数 * o : 引数(省略可)の個数 * r : 可変長引数を受け取るとき1 * m2 : 不明。0以外を使っているところを見たことがない…。 * k : 未使用 * kd : 未使用 * b : ブロック引数(&block)を受け取るとき1 現在のproc(ci->proc)のフラグがMRB_PROC_STRICTを持っているときは、引数の個数チェックを行う。 逆に言うと、STRICTフラグがないのはeachなどのイテレータブロックを呼び出す場合。Hash#eachだと受け側ブロックの引数が一つだと [key, value]で受け取れるし、二つだと key, value となる。この曖昧さはSTRICTを外すことで得られている。 受け取り側の引数の数でci->argcを上書きしたあと、引数の個数差に応じて調整を行う。 * 実際に与えられた個数(argc)が受け取り数(len)より少ない場合 - ブロック引数を適切な位置(regs[len+1])にコピーする - (argc-m2)個を、argvからregs[1]にコピーする(配列渡しなど、argvとregs[1]が別領域の場合のみ) - (m2)個をargv[argc-m2]からregs[len-m2-1]に移動する(m2>0の場合) - regs[m1+o+1]に空の配列を作成する(r==1の場合) - ジャンプする * o==0の場合、通常どおりpc++して次の命令へ * o!=0の場合、pc+=(argc-m1-m2+1)してその命令へ。 * 省略可能引数がある場合、その省略値をロードする命令群が含まれる。それらへのJMP命令をENTER命令の直後に省略可能引数の個数(o)だけ並べるルール。 * 実際に与えられた個数(argc)が受け取り数(len)以上の場合 - (m1+o)個を、argvからregs[1]にコピーする(配列渡しなど、argvとregs[1]が別領域の場合のみ) - 可変長引数がある場合、regs[m1+o+1]に配列を作成する(配列の内容は(argv+m1+o)から、(argc-m1-o-m2)個) - (m2)個をargv[argc-m2]からregs[m1+o+r+1]に移動する(m2>0の場合) - ブロック引数を適切な位置(regs[len+1])にコピーする - pc+=(o+1)して、その命令へ (省略可能引数のジャンプテーブル末端へ飛ばす) ===== OP_KARG (0x27) ===== 未実装 FIXME ===== OP_KDICT (0x28) ===== 未実装 FIXME ===== OP_RETURN (0x29) ===== OP_RETURN A --> retrun R(A) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 0101001 ||||||| * 例外(mrb->exc)がある場合【L_RAISE処理】 - 例外オブジェクト(以下exc)の@lastpcにpcを保存 - excの@ciidxに現在のciの位置(cibaseからのインデックス)を保存 - ciがcibaseと同じ(つまり最上位フレームに居る)場合、ci->ridxが非0であればL_RESCUE処理へ。ci->irdxが0であればL_STOPへ。 - 現在のridxと一つ上位(ci[-1])のridxが異なる値になるまで、以下を繰り返し - callinfoバッファから1つpop - popしたciのaccが-1かつmrb_run開始時のmrb->jmpが非NULLの場合、上位のmrb_runにてsetjmpが設定されている(≒擬似的なtryブロックの中にいる)とみなし、longjmp(1)でthrowする。 * 上位mrb_runのcatch節はL_RAISEの先頭へ飛んでくる。 * 要するに、mrb_runの再帰呼び出しで処理している間に起きた例外を、最上位のmrb_runで吸収するための機構と思われる。 - ensureバッファにある内容について、pop後の最下位ci->eidxより大きいものをすべてecall - mrb->ciがmrb->cibaseに達していたら、ループ終了しL_RESCUE処理へ * このとき、ci->ridx==0の場合はregs、stackをスタック先頭に戻し、L_STOP処理へ。 - ここから【L_RESCUE処理】 - irepをci->procのirepに設定、pool,symsも新irepに合わせて変更する - regs、stackをci[1].stackidxを用いて戻す。 - pcをrescueバッファの[--ci->ridx]番目に設定してそこから実行再開 * 例外がない場合 * B=OP_R_RETURN(2)の場合 - proc->envがNULL、または、現在いるprocがSTRICTの場合はOP_R_NOMRALの処理へ移動 - FIXME * B=OP_R_NORMAL(0)の場合 - mrb->ciがcallinfoバッファの先頭の場合、returnできない所にいるはずなので"LocalJumpError: unexpected return"を起こすためL_RAISEへ。 - ローカル変数ciをmrb->ciとする。 * B=OP_R_BREAK(1)の場合 - proc->env->cioffが負の場合、breakするべきブロック内に居ないことになるので"LocalJumpError: unexpected break"を起こすためL_RAISEへ。 - ローカル変数ci、mrb->ciをcallinfoバッファの[proc->env->cioff+1]番目とする。 - callinfoバッファを1つpop - ===== OP_TAILCALL (0x2a) ===== 01/16現在、ディスアセンブリのみ対応。コード生成箇所無し。FIXME ===== OP_BLKPUSH (0x2b) ===== FIXME ===== OP_ADD (0x2c) ===== FIXME ===== OP_ADDI (0x2d) ===== FIXME ===== OP_SUB (0x2e) ===== FIXME ===== OP_SUBI (0x2f) ===== FIXME ===== OP_MUL (0x30) ===== FIXME ===== OP_DIV (0x31) ===== FIXME ===== OP_EQ (0x32) ===== OP_EQ A, B, C --> R(A) := R(A) == R(A+1) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B (mSyms[B]=:''=='') ||||||||| C (0000001) ||||||| 0110010 ||||||| ===== OP_LT (0x33) ===== OP_EQ A, B, C --> R(A) := R(A) == R(A+1) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B (mSyms[B]=:''<'') ||||||||| C (0000001) ||||||| 0110011 ||||||| ===== OP_LE (0x34) ===== OP_EQ A, B, C --> R(A) := R(A) == R(A+1) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B (mSyms[B]=:''<''''='') ||||||||| C (0000001) ||||||| 0110100 ||||||| ===== OP_GT (0x35) ===== OP_EQ A, B, C --> R(A) := R(A) == R(A+1) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B (mSyms[B]=:''>'') ||||||||| C (0000001) ||||||| 0110101 ||||||| ===== OP_GE (0x36) ===== OP_EQ A, B, C --> R(A) := R(A) == R(A+1) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B (mSyms[B]=:''>='') ||||||||| C (0000001) ||||||| 0110110 ||||||| ===== OP_ARRAY (0x37) ===== OP_ARRAY A, B, C (C>0) --> R(A) := ary_new(R(B), R(B+1), ..., R(B+C)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C (0000001) ||||||| 0110111 ||||||| ===== OP_ARYCAT (0x38) ===== OP_ARYCAT A, B --> ary_cat(R(A), R(B)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 0111000 ||||||| ===== OP_ARYPUSH (0x39) ===== OP_ARYPUSH A, B --> ary_push(R(A), R(B)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 0111001 ||||||| ===== OP_AREF (0x3a) ===== OP_AREF A, B, C --> R(A) := R(B)[C] ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 0111010 ||||||| 配列の要素参照。ただし、言語仕様上で配列扱いとなる部分に対して使われる。なお、R(B)が配列では無い場合、エラーとはならずR(A)にnilが代入される。 # 次の例はOP_AREFではなく、ただの[]メソッド呼び出しである。 b = a[1] # 000 OP_MOVE R4 (a) # 001 OP_LOADI R5 1 # 002 OP_SEND R4 :[] 1 # 次のように多重代入を行う場合は、a,b,cに代入すべき値の取り出しがOP_AREFで行われる。 a,b,c = foo # 000 OP_MOVE R4 (foo) # 001 OP_AREF R1 R4 0 # 002 OP_AREF R2 R4 1 # 003 OP_AREF R3 R4 2 ===== OP_ASET (0x3b) ===== OP_ASET A, B, C --> R(B)[C] := R(A) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 0111011 ||||||| OP_AREFの反対で、配列への代入。FIXME 現時点では使われている様子がない。 ===== OP_APOST (0x3c) ===== OP_APOST A, B, C --> *R(A), R(A+1), ..., R(A+C) := R(A) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 0111100 ||||||| ===== OP_STRING (0x3d) ===== OP_STRING A, Bx --> R(A) := str_dup(Lit(Bx)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 0111101 ||||||| Lit(Bx)にある文字列をもつStringのインスタンスを生成し、R(A)に代入する。 ===== OP_STRCAT (0x3e) ===== OP_STRCAT A, B --> str_cat(R(A), R(B)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 0111110 ||||||| 文字列R(A)の末端に文字列R(B)を連結する。R(A)に対しては破壊的。R(B)は破壊されない。 FIXME R(A)やR(B)がStringでなかった場合は? ===== OP_HASH (0x3f) ===== OP_HASH A, B, C --> R(A) := hash_new(R(B), R(B+1), ..., R(B+C)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 0111111 ||||||| ===== OP_LAMBDA (0x40) ===== OP_LAMBDA A, b, c--> R(A) := lambda(SEQ[b], c) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| b |||||||||||||| c || 1000000 ||||||| ===== OP_RANGE (0x41) ===== OP_RANGE A, B, C --> R(A) := range_new(R(B), R(B+1), C) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| C ||||||| 1000001 ||||||| ===== OP_OCLASS (0x42) ===== OP_OCLASS A --> R(A) := ::Object ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 1000010 ||||||| ::ObjectをR(A)に代入する。 ===== OP_CLASS (0x43) ===== OP_CLASS A, B --> R(A) := newclass(R(A), mSym(B), R(A+1)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 1000011 ||||||| クラスを定義する。R(A)はbase(たいていnil入れてるけど何これ?FIXME)、R(A+1)はsuper。 ===== OP_MODULE (0x44) ===== OP_MODULE A, B --> R(A) := newmodule(R(A), mSym(B)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 1000100 ||||||| ===== OP_EXEC (0x45) ===== OP_EXEC A, Bx --> R(A) := blockexec(R(A), SEQ[Bx]) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| Bx |||||||||||||||| 1000101 ||||||| ===== OP_METHOD (0x46) ===== OP_METHOD A, B --> R(A).newmethod(mSym(B), R(A+1)) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 1000110 ||||||| ===== OP_SCLASS (0x47) ===== OP_SCLASS A, B --> R(A) := R(B).singleton_class ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| B ||||||||| | | | | | | | 1000111 ||||||| R(B)のクラスを元として、singletonクラスを作成する。singletonクラスとは、元のクラスと同じ機能を継承した上で、特異メソッドなどを持つインスタンス固有のクラス。 なお、singletonクラスに対して OP_SCLASS を実行すると、FIXME ===== OP_TCLASS (0x48) ===== OP_TCLASS A --> R(A) := target_class ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 1001000 ||||||| ===== OP_DEBUG (0x49) ===== OP_DEBUG A --> print R(A) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | A ||||||||| | | | | | | | | | | | | | | | | 1001001 ||||||| ===== OP_STOP (0x4a) ===== OP_STOP --> Stop VM ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | | | | | | | | | | | | | | | | | 1001010 ||||||| ===== OP_ERR (0x4b) ===== OP_ERR Bx --> raise RuntimeError with message Lit(Bx) ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | Bx |||||||||||||||| 1001011 ||||||| ===== OP_RSVD1 (0x4c) ===== Reserved instruction #1 ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | | | | | | | | | | | | | | | | | 1001100 ||||||| ===== OP_RSVD1 (0x4d) ===== Reserved instruction #2 ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | | | | | | | | | | | | | | | | | 1001101 ||||||| ===== OP_RSVD1 (0x4e) ===== Reserved instruction #3 ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | | | | | | | | | | | | | | | | | 1001110 ||||||| ===== OP_RSVD1 (0x4f) ===== Reserved instruction #4 ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | | | | | | | | | | | | | | | | | 1001111 ||||||| ===== OP_RSVD1 (0x50) ===== Reserved instruction #5 ^31^30^29^28^27^26^25^24^23^22^21^20^19^18^17^16^15^14^13^12^11^10^09^08^07^06^05^04^03^02^01^00^ | | | | | | | | | | | | | | | | | | | | | | | | | | 1010000 |||||||