YARVアーキテクチャ

by 日本 Ruby の会 ささだこういち / Fri Mar 04 16:17:04 2005


これは?

YARV: Yet Another RubyVM の 設計メモです。

YARV は、Ruby プログラムのための次の機能を提供します。

現在の YARV は Ruby インタプリタの拡張ライブラリとして実装しています。こ れにより、Ruby インタプリタの必要な機能(パーサ、オブジェクト管理、既存 の拡張ライブラリ)などがほぼそのまま利用できます。

ただし、いくつかのパッチを Ruby インタプリタに当てなければなりません。

今後は、Ruby 本体のインタプリタ部分(eval.c)を置き換えることを目指して 開発を継続する予定です。

Compiler (compile.h, compile.c)

コンパイラは、Ruby インタプリタのパーサによって生成された構文木(RNode データによる木)を YARV 命令列に変換します。YARV 命令については後述しま す。

とくに難しいことはしていませんが、スコープなどの開始時にローカル変数の初 期化などを行い、あとは構文木を辿り変換していきます。

変換中は Ruby の Array オブジェクトに YARV 命令オブジェクト、およびオペ ランドを格納していき、最後に実行できる形に変換します。コンパイラでは、コ ンパイル中に生成するメモリ領域の管理が問題になることがありますが、YARV の場合、Ruby インタプリタがすべて面倒をみてくれるのでこの部分は非常に楽 に作ることができました(ガーベージコレクタによって自動的にメモリ管理をし てくれるため)。

YARV 命令は、命令を示す識別子、オペランドなど、すべて 1 word (マシンで 表現できる自然な値。C 言語ではポインタのサイズ。Ruby インタプリタ用語で は VALUE のサイズ)で表現されます。そのため、YARV 命令はいわゆる「バイト コード」ではありません。そのため、YARV の説明などでは「命令列」という用 語を使っています。

1 word であるため、メモリの利用効率は多少悪くなりますが、アクセス速度な どを考慮すると、本方式が一番いいと考えております。たとえばオペランドをコ ンスタントプールに格納し、インデックスのみをオペランドで示すことも可能で すが、間接アクセスになってしまうので性能に影響が出るため、却下しました。

VM Generator (rb/insns2vm.rb, insns.def)

rb/insns2vm.rb というスクリプトは、insns.def というファイルを読み込み、 VM のために必要なファイルを生成します。具体的には、命令を実行する部分を 生成しますが、ほかにもコンパイルに必要な情報、最適化に必要な情報、やアセ ンブラ、逆アセンブラに必要な情報を示すファイルも生成します。

命令記述

insns.def には、各命令がどのような命令であるかを記述します。具体的には次 の情報を記述します。

たとえば、スタックに self をおく putself という命令は次のように記述しま す。

/**
  @c put
  @e put self.
  @j self を置く。
 */
DEFINE_INSN
putself
()
()
(VALUE val)
{
  val = GET_SELF();
}

この場合、オペランドと、スタックからポップする値は無いことになります。命 令終了後、self をスタックトップに置きたいわけですが、それは val という、 スタックにプッシュする値として宣言しておいた変数に代入しておくことで、こ れを変換するとスタックトップに置く C プログラムが生成されます。

細かいフォーマットは insns.def の冒頭を参照してください。そんなに難しく ないと思います。

insnhelper.h というファイルに、命令ロジックを記述するために必要なマクロ が定義されています。また、VM の内部構造に関する定義は vm.h というファイ ルにあります。

VM (Virtual Machine, vm.h, vm.c)

VM は、実際にコンパイルした結果生成される YARV 命令列を実行します。まさ に、この部分が YARV のキモになり、将来的には eval.c をこの VM で置き換え たいと考えています。

現在の Ruby インタプリタで実行できるすべてのことが、この VM で実現できる ように作っています(現段階ではまだ完全ではありませんが、そうなるべきです)。

VM は、単純なスタックマシンとして実装しています。スレッドひとつにスタッ クひとつを保持します。スタックの領域はヒープから取得するので、柔軟な領域 設定が可能です。

レジスタ

VM は 5 つの仮想的なレジスタによって制御されます。

PC は現在実行中の命令列の位置を示します。SP はスタックトップの位置を示し ます。CFP、LFP、DFP はそれぞれフレームの情報を示します。詳細は後述します。

スタックフレーム

変数スコープを別々にするため、実現するため、いくつかの種類のスタックフレ ームを生成します。なお、命令列はスコープ単位で別々のオブジェクトとして作 られます。

スタックフレームの種類は次の 3 種類です。

メソッドフレームはメソッドを起動するごとに生成されます。独立したスコープ を持ちます。ブロックフレームはブロックを起動したごとに生成されます。ブロ ックのスコープは、それより上位のスコープを見ることができます。クラスフレ ームはクラス定義、モジュール定義の場合に生成されます。このスコープも独立 しています。

メソッドフレームとクラスフレームはほぼ同じです。

各フレームの構造はだいたい次のようになっています。

                           <- 継続フレーム ----->
     <-  引数  -> <-  変数  ->        <- 制御フレーム ---------------->
-------------------------------+-----+-----------+----------------------+----
self a1 a2 ... aM l1 l2 ... lN | XXX | self iseq | MAGIC pc cfp lfp dfp | ...
-------------------------------+-----+-----------+----------------------+----
                                       ^
                                       cfp
--> スタック深い

XXXX の部分は、スコープのタイプによる。
メソッドフレームの場合: ブロック
ブロックフレームの場合: 直前のフレームへのポインタ
クラスフレームの場合  : nil

制御フレームは、そのフレームを管理するための情報が格納されています。

iseq は命令列の情報です。MAGIC はそのフレームの種類をしめす値(Fixnum) が格納されています。将来的に YARV が安定したらこれを外すことを検討してい ます。

継続フレームは前のフレームの情報が入っており、そのスコープから抜けるとき に継続フレームの情報をレジスタに欠き戻します。

cfp[0] ではどのフレームでも self を取得することができます。また、同様に cfp[1] も iseq (現在実行している命令列の情報)を得ることができます。

メソッドローカルフレーム

メソッドディスパッチ命令 send を実行すると、メソッドフレームが作られます。

-------------------------------+-----+-----------+----------------------+----
self a1 a2 ... aM l1 l2 ... lN | blo | self iseq | MAGIC pc cfp lfp dfp | ...
-------------------------------+-----+-----------+----------------------+----
                                 ^     ^
                                 lfp   cfp
                                 dfp

a1 から aM は M個のメソッドの引数で、l1 から lN は N個のメソッドローカル 変数を示します。これらの引数は callee が配置しておきます(正確には、send 時に rest 引数などを決定します)。

self はそのメソッドのレシーバです。ブロックはそのメソッド呼び出しにブロ ックが指定されているかどうか、されているならどのようなブロックが指定され たかの情報を示します。

ローカル変数には、lfp[-X] という形でアクセスします。これらのインデックス はコンパイル時(正確には parse 時)に決定します。

ブロックローカルフレーム

ブロックが Proc#callやyield などにより起動されたときにできるスコープを表 現するためのフレーム構造です。継続フレームとあわせて次のような配置になり ます。

(ローカルメソッドフレーム)
-------------------------------+-----+-----------+----------------------+----
self a1 a2 ... aM l1 l2 ... lN | blo | self iseq | MAGIC pc cfp lfp dfp | ...
-------------------------------+-----+-----------+----------------------+----
                                 ^
                                 lfp

(ブロックローカルフレーム1)
-------------------------------+-----+-----------+----------------------+----
self a1 a2 ... aM l1 l2 ... lN | pre | self iseq | MAGIC pc cfp lfp dfp | ...
-------------------------------+-----+-----------+----------------------+----

(ブロックローカルフレーム2)
-------------------------------+-----+-----------+----------------------+----
self a1 a2 ... aM l1 l2 ... lN | pre | self iseq | MAGIC pc cfp lfp dfp | ...
-------------------------------+-----+-----------+----------------------+----
                                 ^     ^
                                 dfp   cfp

これは、次のような Ruby プログラムを実行したときに相当します。

def m(a1, ..., aM)
  l1 = ...; ...; lN = ...;
  method_foo(){|...|
    # Block1
    method_bar(){|...|
      # Block2
      ...(running)...
    }
  }
end

LFP はメソッドローカル変数を必ずアクセスすることができます。dfp はブロッ クローカル変数をアクセスすることができます。pre を利用していくつかのフレ ームをさかのぼることが出来ます。

クラスフレーム

クラス・モジュールを定義中のスコープを表現するためのフレーム構造で、継続 フレームとあわせて次のようになります。

-------------+-----+-----------+----------------------+----
l1 l2 ... lN | nil | self iseq | MAGIC pc cfp lfp dfp | ...
-------------+-----+-----------+----------------------+----
               ^     ^
               lfp   cfp
               dfp

メソッドローカルフレームと違い、引数とブロックがありません。

self はその定義中のクラス・モジュールのインスタンスが格納されています。

フレームデザインについての補足

Lisp の処理系などをかんがえると、わざわざブロックローカルフレームとメソ ッドローカルフレームのようなものを用意するのは奇異に見えるかもしれません。 あるフレームを、入れ子構造にして、ローカル変数のアクセスはその入れ子を外 側に辿れば必ずたどり着くことができるからです(つまり、lfp は必要ない)。

しかし、Ruby ではいくつか状況が違います。まず、メソッドローカルな情報が あること、具体的にはブロックとself(callee からみると reciever)です。こ の情報をそれぞれのフレームにもたせるのは無駄です。

また、Ruby2.0 からはブロックローカル変数はなくなります(ブロックローカル 引数は残るので、構造自体はあまり変わりません)。そのため、メソッドローカ ル変数へのアクセスが頻発することが予想されます。

このとき、メソッドローカル変数へのアクセスのたびにフレーム(スコープ)の リストをたどるのは無駄であると判断し、明示的にメソッドローカルスコープと ブロックフレームを分離し、ブロックフレームからはメソッドローカルフレーム が lfpレジスタによって容易にアクセスできるようにしました。

メソッド呼び出しについて

メソッド呼び出しは、YARV 命令列で記述されたメソッドか、C で記述されたメ ソッドかによってディスパッチ手法が変わります。

YARV 命令列であった場合、上述したスタックフレームを作成して命令を継続し ます。とくに VM の関数を再帰呼び出すすることは行ないません。

C で記述されたメソッドだった場合、単純にその関数を呼び出します(ただし、 バックトレースを正しく生成するためにメソッド呼び出しの情報を付加してから 行ないます)。

このため、VM 用スタックを別途用意したものの、プログラムによってはマシン スタックを使い切ってしまう可能性があります(C -> Ruby -> C -> ... という 呼び出しが続いた場合)。これは、現在では避けられない仕様となっています。

例外

例外は、Java の JVM と同様に例外テーブルを用意することで実現します。例外 が発生したら、当該フレームを、例外テーブルを検査します。そこで、例外が発 生したときの PC の値に合致するエントリがあった場合、そのエントリに従って 動作します。もしエントリが見つからなかった場合、スタックを撒き戻してまた 同様にそのスコープの例外テーブルを検査します。

また、break、return(ブロック中)、retry なども同様の仕組みで実現します。

例外テーブル

例外テーブルエントリは具体的には次の情報が格納されています。

rescue

rescue 節はブロックとして実現しています。$! の値を唯一の引数として持ちま す。

begin
rescue A
rescue B
rescue C
end

は、次のような Ruby スクリプトに変換されます。

{|err|
  case err
  when A === err
  when B === err
  when C === err
  else
    raise # yarv の命令では throw
  end
}

ensure

正常系(例外が発生しなかった場合)と異常系(例外が発生したときなど)の2 種類の命令列が生成されます。正常系では、ただの連続したコード領域としてコ ンパイルされます。また、異常系ではブロックとして実装します。最後は必ず throw 命令で締めることになります。

break, return(ブロック中)、retry

break 文、ブロック中の return 文、retry 文は throw 命令としてコンパイル されます。どこまで戻るかは、break をフックする例外テーブルのエントリが判 断します。

定数の検索

定数という名前なのに、Ruby ではコンパイル時に決定しません。というか、い つまでも再定義可能になっています。

定数アクセスのためのRuby記述は次のようになります。

Ruby表現:
expr::ID::...::ID

これは、yarv命令セットでは次のようになります。

(expr)
getconstant ID
...
getconstant ID

定数検索パス

もし expr が nil だった場合、定数検索パスに従って定数を検索します。この 挙動は今後 Ruby 2.0 に向けて変更される場合があります。

  1. クラス、モジュールの動的ネスト関係(プログラムの字面上)をルートまで辿る
  2. 継承関係をルート(Object)まで辿る

このため、クラス、モジュールの動的ネスト関係を保存しなければなりません。 このために、thread_object には klass_nest_stack というものを用意しました。 これは、現在のネストの情報を保存します。

メソッド定義時、その現在のネスト情報をメソッド定義時に(dupして)加える ことで、そのメソッドの実行時、そのネスト情報を参照することが可能になりま す。

トップレベルでは、その情報はないことになります。

クラス/モジュール定義文実行時は、現在の情報そのものを参照することになり ます。これは、クラススコープ突入時、その情報をクラス定義文にコピーします (すでにコピーされていれば、これを行いません)。

これにより、動的なネスト情報を統一的に扱うことができます。

最適化手法

YARV では高速化を目的としているので、さまざまな最適化手法を利用していま す。詳細は割愛しますが、以下に述べる最適化などを行なっております。

threaded code

GCC の C 言語拡張である値としてのラベルを利用して direct threaded code を実現しています。

Peephole optimization

いくつかの簡単な最適化をしています。

inline method cache

命令列の中にメソッド検索結果を埋め込みます。

inline constant cache

命令列の中に定数検索結果を埋め込みます。

ブロックと Proc オブジェクトの分離

ブロック付きメソッド呼び出しが行なわれたときにはすぐにはブロックを Proc オブジェクトとして生成しません。これにより、必要ない Proc オブジェクトの 生成を抑えています。

Proc メソッドは、実際に必要になった時点で作られ、そのときに環境(スコー プ上に確保された変数など)をヒープに保存します。

特化命令

Fixnum 同士の加算などを正直に関数呼び出しによって行なうと、コストがかか るので、これらのプリミティブな操作を行なうためのメソッド呼び出しは専用命 令を用意しました。

命令融合

複数の命令を 1 命令に変換します。融合命令は opt_insn_unif.def の記述によ り自動的に生成されます。

オペランド融合

複数のオペランドを含めた命令を生成します。融合命令は opt_operand.def の 記述によって自動的に生成されます。

stack caching

スタックトップを仮想レジスタに保持するようにします。現在は 2 個の仮想レ ジスタを想定し、5状態のスタックキャッシングを行ないます。スタックキャッ シングする命令は自動的に生成されます。

JIT Compile

機械語を切り貼りします。非常に実験的なコードものしか作っておりません。ほ とんどのプログラムは動きません。

AOT Compile

YARV 命令列を C 言語に変換します。まだ十分な最適化を行なえておりませんが、 それなりに動きます。rb/aotc.rb がコンパイラです。

Assembler (rb/yasm.rb)

YARV 命令列のアセンブラを用意しました。使い方は rb/yasm.rb を参照してく ださい(まだ、例示してある生成手法のすべてをサポートしているわけではあり ません)。

Dis-Assembler (disasm.c)

YARV 命令列を示すオブジェクト YARVCore::InstructionSequence には disasm メソッドがあります。これは、命令列を逆アセンブルした文字列を返します。

YARV 命令セット

nop

nop

nop

instruction sequence
0x00
stack
=>

variable

getlocal

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x01 idx
stack
=> val

setlocal

idx で指定されたローカル変数を val にする。

instruction sequence
0x02 idx
stack
val =>

getspecial

特殊なローカル変数の値を得る

instruction sequence
0x03 idx type
stack
=> val

setspecial

特別なローカル変数を設定する

instruction sequence
0x04 idx type
stack
obj =>

getdynamic

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x05 idx level
stack
=> val

setdynamic

level, idx で指定されたブロックローカル変数の値を val にする。

instruction sequence
0x06 idx level
stack
val =>

getinstancevariable

obj のインスタンス変数 id を得る。

instruction sequence
0x07 id
stack
=> val

setinstancevariable

obj のインスタンス変数を val にする。

instruction sequence
0x08 id
stack
val =>

getclassvariable

klass のクラス変数 id を得る。

instruction sequence
0x09 id
stack
=> val

setclassvariable

klass のクラス変数 id を val にする。

instruction sequence
0x0a id declp
stack
val =>

getconstant

instruction sequence
0x0b id
stack
klass => val

setconstant

instruction sequence
0x0c id
stack
val klass =>

getglobal

グローバル変数 id を得る。

instruction sequence
0x0d entry
stack
=> val

setglobal

グローバル変数 id を得る。

instruction sequence
0x0e entry
stack
val =>

put

putnil

put nil

instruction sequence
0x0f
stack
=> val

putself

self を置く。

instruction sequence
0x10
stack
=> val

putobject

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x11 val
stack
=> val

putstring

文字列を置く。文字列はコピーしとく。

instruction sequence
0x12 val
stack
=> val

concatstrings

文字列を連結して置く。

instruction sequence
0x13 num
stack
... => val

tostring

to_str

instruction sequence
0x14
stack
val => val

toregexp

to Regexp

instruction sequence
0x15 flag
stack
str => val

newarray

新しい配列をスタック上の num 個の値で初期化して置く。

instruction sequence
0x16 num
stack
... => val

duparray

配列を dup してスタックに置く

instruction sequence
0x17 ary
stack
=> val

expandarray

スタックトップのオブジェクトが配列であれば、それを展開する。

instruction sequence
0x18 num flag
stack
... ary => ...

newhash

Hash.new

instruction sequence
0x19 num
stack
... => val

newrange

Range.new(low, high, flag) のようなオブジェクトを置く。

instruction sequence
0x1a flag
stack
low high => val

putnot

!val であるオブジェクトを置く。

instruction sequence
0x1b
stack
obj => val

stack

pop

スタックから一つポップする。

instruction sequence
0x1c
stack
val =>

dup

スタックトップをコピーしてスタックにおく

instruction sequence
0x1d
stack
val => val1 val2

dupn

スタックトップから n 個をコピーしてスタックにおく

instruction sequence
0x1e n
stack
... => ...

swap

スタックトップの2つを交換する。

instruction sequence
0x1f
stack
val obj => obj val

reput

instruction sequence
0x20
stack
... val => val

topn

スタックトップから n 個目をスタックトップにコピー

instruction sequence
0x21 n
stack
... => val

setting

methoddef

メソッド m を body として定義する。

instruction sequence
0x22 id body
stack
=>

singletonmethoddef

特異メソッド m を body として obj に定義する。

instruction sequence
0x23 id body
stack
obj =>

alias

alias を作る。もし v_p が Qtrue なら、valias (global variable) を作る

instruction sequence
0x24 v_p id1 id2
stack
=>

undef

undef

instruction sequence
0x25 id
stack
=>

defined

defined?

instruction sequence
0x26 type obj needstr
stack
... => val

class/module

classdef

instruction sequence
0x27 id klass_iseq
stack
cbase super => val

singletonclassdef

特異クラス定義スコープへ移行する。

instruction sequence
0x28 sclass_iseq
stack
obj => val

moduledef

モジュール定義スコープへ移行する。

instruction sequence
0x29 id module_iseq
stack
mbase => val

popcref

クラスのネスト関係情報をひとつポップする

instruction sequence
0x2a
stack
=>

method/iterator

send

obj.send(id, args) # args.size => num

instruction sequence
0x2b id argc block flag ic
stack
... => val

super

super(args) # args.size => num

instruction sequence
0x2c num flag
stack
... => val

zsuper

super

instruction sequence
0x2d
stack
... => val

yield

yield(args) # args.size => num

instruction sequence
0x2e num flag
stack
... => val

end

このスコープから抜ける。

instruction sequence
0x2f idx
stack
val => val

exception

throw

longjump

instruction sequence
0x30 throw_state
stack
throwobj =>

jump

jump

PC を (PC + dst) にする。

instruction sequence
0x31 dst
stack
=>

if

もし val が false か nil でなければ、PC を (PC + dst) にする。

instruction sequence
0x32 dst
stack
val =>

unless

もし val が false か nil ならば、PC を (PC + dst) にする。

instruction sequence
0x33 dst
stack
val =>

optimize

getinlinecache

inline cache

instruction sequence
0x34 ic dst
stack
=> val

setinlinecache

set inline cahce

instruction sequence
0x35 dst
stack
val => val

opt_plus

最適化された X+Y。

instruction sequence
0x36
stack
recv obj => val

opt_minus

最適化された X-Y。

instruction sequence
0x37
stack
recv obj => val

opt_lt

最適化された X<Y。

instruction sequence
0x38
stack
recv obj => val

opt_ltlt

<<

instruction sequence
0x39
stack
recv obj => val

opt_regexpmatch1

最適化された正規表現マッチ

instruction sequence
0x3a r
stack
obj => val

opt_regexpmatch2

最適化された正規表現マッチ 2

instruction sequence
0x3b
stack
obj2 obj1 => val

opt_call_native_compiled

ネイティブコンパイルしたメソッドを kick

instruction sequence
0x3c
stack
=>

getlocal_OP_1

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x3d
stack
=> val

setlocal_OP_1

idx で指定されたローカル変数を val にする。

instruction sequence
0x3e
stack
val =>

getlocal_OP_2

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x3f
stack
=> val

setlocal_OP_2

idx で指定されたローカル変数を val にする。

instruction sequence
0x40
stack
val =>

getdynamic_OP__WC__0

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x41 idx
stack
=> val

getdynamic_OP_1_0

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x42
stack
=> val

putobject_OP_INT2FIX_O_0_C_

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x43
stack
=> val

putobject_OP_INT2FIX_O_1_C_

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x44
stack
=> val

putobject_OP_Qtrue

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x45
stack
=> val

putobject_OP_Qfalse

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x46
stack
=> val

send_OP__WC___WC__Qfalse_0__WC_

obj.send(id, args) # args.size => num

instruction sequence
0x47 id argc ic
stack
... => val

UNIFIED_putobject_putobject

unified insn

instruction sequence
0x48 val_0 val_1
stack
=> val_0 val_1

UNIFIED_putstring_putstring

unified insn

instruction sequence
0x49 val_0 val_1
stack
=> val_0 val_1

UNIFIED_putstring_putobject

unified insn

instruction sequence
0x4a val_0 val_1
stack
=> val_0 val_1

UNIFIED_putobject_putstring

unified insn

instruction sequence
0x4b val_0 val_1
stack
=> val_0 val_1

optimize(sc)

nop_SC_xx_xx

nop

instruction sequence
0x4c
stack
=>

nop_SC_ax_ax

nop

instruction sequence
0x4d
stack
=>

nop_SC_bx_bx

nop

instruction sequence
0x4e
stack
=>

nop_SC_ab_ab

nop

instruction sequence
0x4f
stack
=>

nop_SC_ba_ba

nop

instruction sequence
0x50
stack
=>

getlocal_SC_xx_ax

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x51 idx
stack
=> val

getlocal_SC_ax_ab

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x52 idx
stack
=> val

getlocal_SC_bx_ba

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x53 idx
stack
=> val

getlocal_SC_ab_ba

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x54 idx
stack
=> val

getlocal_SC_ba_ab

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x55 idx
stack
=> val

setlocal_SC_xx_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x56 idx
stack
val =>

setlocal_SC_ax_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x57 idx
stack
val =>

setlocal_SC_bx_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x58 idx
stack
val =>

setlocal_SC_ab_ax

idx で指定されたローカル変数を val にする。

instruction sequence
0x59 idx
stack
val =>

setlocal_SC_ba_bx

idx で指定されたローカル変数を val にする。

instruction sequence
0x5a idx
stack
val =>

getspecial_SC_xx_ax

特殊なローカル変数の値を得る

instruction sequence
0x5b idx type
stack
=> val

getspecial_SC_ax_ab

特殊なローカル変数の値を得る

instruction sequence
0x5c idx type
stack
=> val

getspecial_SC_bx_ba

特殊なローカル変数の値を得る

instruction sequence
0x5d idx type
stack
=> val

getspecial_SC_ab_ba

特殊なローカル変数の値を得る

instruction sequence
0x5e idx type
stack
=> val

getspecial_SC_ba_ab

特殊なローカル変数の値を得る

instruction sequence
0x5f idx type
stack
=> val

setspecial_SC_xx_xx

特別なローカル変数を設定する

instruction sequence
0x60 idx type
stack
obj =>

setspecial_SC_ax_xx

特別なローカル変数を設定する

instruction sequence
0x61 idx type
stack
obj =>

setspecial_SC_bx_xx

特別なローカル変数を設定する

instruction sequence
0x62 idx type
stack
obj =>

setspecial_SC_ab_ax

特別なローカル変数を設定する

instruction sequence
0x63 idx type
stack
obj =>

setspecial_SC_ba_bx

特別なローカル変数を設定する

instruction sequence
0x64 idx type
stack
obj =>

getdynamic_SC_xx_ax

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x65 idx level
stack
=> val

getdynamic_SC_ax_ab

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x66 idx level
stack
=> val

getdynamic_SC_bx_ba

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x67 idx level
stack
=> val

getdynamic_SC_ab_ba

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x68 idx level
stack
=> val

getdynamic_SC_ba_ab

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x69 idx level
stack
=> val

setdynamic_SC_xx_xx

level, idx で指定されたブロックローカル変数の値を val にする。

instruction sequence
0x6a idx level
stack
val =>

setdynamic_SC_ax_xx

level, idx で指定されたブロックローカル変数の値を val にする。

instruction sequence
0x6b idx level
stack
val =>

setdynamic_SC_bx_xx

level, idx で指定されたブロックローカル変数の値を val にする。

instruction sequence
0x6c idx level
stack
val =>

setdynamic_SC_ab_ax

level, idx で指定されたブロックローカル変数の値を val にする。

instruction sequence
0x6d idx level
stack
val =>

setdynamic_SC_ba_bx

level, idx で指定されたブロックローカル変数の値を val にする。

instruction sequence
0x6e idx level
stack
val =>

getinstancevariable_SC_xx_ax

obj のインスタンス変数 id を得る。

instruction sequence
0x6f id
stack
=> val

getinstancevariable_SC_ax_ab

obj のインスタンス変数 id を得る。

instruction sequence
0x70 id
stack
=> val

getinstancevariable_SC_bx_ba

obj のインスタンス変数 id を得る。

instruction sequence
0x71 id
stack
=> val

getinstancevariable_SC_ab_ba

obj のインスタンス変数 id を得る。

instruction sequence
0x72 id
stack
=> val

getinstancevariable_SC_ba_ab

obj のインスタンス変数 id を得る。

instruction sequence
0x73 id
stack
=> val

setinstancevariable_SC_xx_xx

obj のインスタンス変数を val にする。

instruction sequence
0x74 id
stack
val =>

setinstancevariable_SC_ax_xx

obj のインスタンス変数を val にする。

instruction sequence
0x75 id
stack
val =>

setinstancevariable_SC_bx_xx

obj のインスタンス変数を val にする。

instruction sequence
0x76 id
stack
val =>

setinstancevariable_SC_ab_ax

obj のインスタンス変数を val にする。

instruction sequence
0x77 id
stack
val =>

setinstancevariable_SC_ba_bx

obj のインスタンス変数を val にする。

instruction sequence
0x78 id
stack
val =>

getclassvariable_SC_xx_ax

klass のクラス変数 id を得る。

instruction sequence
0x79 id
stack
=> val

getclassvariable_SC_ax_ab

klass のクラス変数 id を得る。

instruction sequence
0x7a id
stack
=> val

getclassvariable_SC_bx_ba

klass のクラス変数 id を得る。

instruction sequence
0x7b id
stack
=> val

getclassvariable_SC_ab_ba

klass のクラス変数 id を得る。

instruction sequence
0x7c id
stack
=> val

getclassvariable_SC_ba_ab

klass のクラス変数 id を得る。

instruction sequence
0x7d id
stack
=> val

setclassvariable_SC_xx_xx

klass のクラス変数 id を val にする。

instruction sequence
0x7e id declp
stack
val =>

setclassvariable_SC_ax_xx

klass のクラス変数 id を val にする。

instruction sequence
0x7f id declp
stack
val =>

setclassvariable_SC_bx_xx

klass のクラス変数 id を val にする。

instruction sequence
0x80 id declp
stack
val =>

setclassvariable_SC_ab_ax

klass のクラス変数 id を val にする。

instruction sequence
0x81 id declp
stack
val =>

setclassvariable_SC_ba_bx

klass のクラス変数 id を val にする。

instruction sequence
0x82 id declp
stack
val =>

getconstant_SC_xx_ax

instruction sequence
0x83 id
stack
klass => val

getconstant_SC_ax_ax

instruction sequence
0x84 id
stack
klass => val

getconstant_SC_bx_ax

instruction sequence
0x85 id
stack
klass => val

getconstant_SC_ab_ab

instruction sequence
0x86 id
stack
klass => val

getconstant_SC_ba_ba

instruction sequence
0x87 id
stack
klass => val

setconstant_SC_xx_xx

instruction sequence
0x88 id
stack
val klass =>

setconstant_SC_ax_xx

instruction sequence
0x89 id
stack
val klass =>

setconstant_SC_bx_xx

instruction sequence
0x8a id
stack
val klass =>

setconstant_SC_ab_xx

instruction sequence
0x8b id
stack
val klass =>

setconstant_SC_ba_xx

instruction sequence
0x8c id
stack
val klass =>

getglobal_SC_xx_ax

グローバル変数 id を得る。

instruction sequence
0x8d entry
stack
=> val

getglobal_SC_ax_ab

グローバル変数 id を得る。

instruction sequence
0x8e entry
stack
=> val

getglobal_SC_bx_ba

グローバル変数 id を得る。

instruction sequence
0x8f entry
stack
=> val

getglobal_SC_ab_ba

グローバル変数 id を得る。

instruction sequence
0x90 entry
stack
=> val

getglobal_SC_ba_ab

グローバル変数 id を得る。

instruction sequence
0x91 entry
stack
=> val

setglobal_SC_xx_xx

グローバル変数 id を得る。

instruction sequence
0x92 entry
stack
val =>

setglobal_SC_ax_xx

グローバル変数 id を得る。

instruction sequence
0x93 entry
stack
val =>

setglobal_SC_bx_xx

グローバル変数 id を得る。

instruction sequence
0x94 entry
stack
val =>

setglobal_SC_ab_ax

グローバル変数 id を得る。

instruction sequence
0x95 entry
stack
val =>

setglobal_SC_ba_bx

グローバル変数 id を得る。

instruction sequence
0x96 entry
stack
val =>

putnil_SC_xx_ax

put nil

instruction sequence
0x97
stack
=> val

putnil_SC_ax_ab

put nil

instruction sequence
0x98
stack
=> val

putnil_SC_bx_ba

put nil

instruction sequence
0x99
stack
=> val

putnil_SC_ab_ba

put nil

instruction sequence
0x9a
stack
=> val

putnil_SC_ba_ab

put nil

instruction sequence
0x9b
stack
=> val

putself_SC_xx_ax

self を置く。

instruction sequence
0x9c
stack
=> val

putself_SC_ax_ab

self を置く。

instruction sequence
0x9d
stack
=> val

putself_SC_bx_ba

self を置く。

instruction sequence
0x9e
stack
=> val

putself_SC_ab_ba

self を置く。

instruction sequence
0x9f
stack
=> val

putself_SC_ba_ab

self を置く。

instruction sequence
0xa0
stack
=> val

putobject_SC_xx_ax

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0xa1 val
stack
=> val

putobject_SC_ax_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0xa2 val
stack
=> val

putobject_SC_bx_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0xa3 val
stack
=> val

putobject_SC_ab_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0xa4 val
stack
=> val

putobject_SC_ba_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0xa5 val
stack
=> val

putstring_SC_xx_ax

文字列を置く。文字列はコピーしとく。

instruction sequence
0xa6 val
stack
=> val

putstring_SC_ax_ab

文字列を置く。文字列はコピーしとく。

instruction sequence
0xa7 val
stack
=> val

putstring_SC_bx_ba

文字列を置く。文字列はコピーしとく。

instruction sequence
0xa8 val
stack
=> val

putstring_SC_ab_ba

文字列を置く。文字列はコピーしとく。

instruction sequence
0xa9 val
stack
=> val

putstring_SC_ba_ab

文字列を置く。文字列はコピーしとく。

instruction sequence
0xaa val
stack
=> val

concatstrings_SC_xx_ax

文字列を連結して置く。

instruction sequence
0xab num
stack
... => val

concatstrings_SC_ax_ax

文字列を連結して置く。

instruction sequence
0xac num
stack
... => val

concatstrings_SC_bx_ax

文字列を連結して置く。

instruction sequence
0xad num
stack
... => val

concatstrings_SC_ab_ax

文字列を連結して置く。

instruction sequence
0xae num
stack
... => val

concatstrings_SC_ba_ax

文字列を連結して置く。

instruction sequence
0xaf num
stack
... => val

tostring_SC_xx_ax

to_str

instruction sequence
0xb0
stack
val => val

tostring_SC_ax_ax

to_str

instruction sequence
0xb1
stack
val => val

tostring_SC_bx_ax

to_str

instruction sequence
0xb2
stack
val => val

tostring_SC_ab_ab

to_str

instruction sequence
0xb3
stack
val => val

tostring_SC_ba_ba

to_str

instruction sequence
0xb4
stack
val => val

toregexp_SC_xx_ax

to Regexp

instruction sequence
0xb5 flag
stack
str => val

toregexp_SC_ax_ax

to Regexp

instruction sequence
0xb6 flag
stack
str => val

toregexp_SC_bx_ax

to Regexp

instruction sequence
0xb7 flag
stack
str => val

toregexp_SC_ab_ab

to Regexp

instruction sequence
0xb8 flag
stack
str => val

toregexp_SC_ba_ba

to Regexp

instruction sequence
0xb9 flag
stack
str => val

newarray_SC_xx_ax

新しい配列をスタック上の num 個の値で初期化して置く。

instruction sequence
0xba num
stack
... => val

newarray_SC_ax_ax

新しい配列をスタック上の num 個の値で初期化して置く。

instruction sequence
0xbb num
stack
... => val

newarray_SC_bx_ax

新しい配列をスタック上の num 個の値で初期化して置く。

instruction sequence
0xbc num
stack
... => val

newarray_SC_ab_ax

新しい配列をスタック上の num 個の値で初期化して置く。

instruction sequence
0xbd num
stack
... => val

newarray_SC_ba_ax

新しい配列をスタック上の num 個の値で初期化して置く。

instruction sequence
0xbe num
stack
... => val

duparray_SC_xx_ax

配列を dup してスタックに置く

instruction sequence
0xbf ary
stack
=> val

duparray_SC_ax_ab

配列を dup してスタックに置く

instruction sequence
0xc0 ary
stack
=> val

duparray_SC_bx_ba

配列を dup してスタックに置く

instruction sequence
0xc1 ary
stack
=> val

duparray_SC_ab_ba

配列を dup してスタックに置く

instruction sequence
0xc2 ary
stack
=> val

duparray_SC_ba_ab

配列を dup してスタックに置く

instruction sequence
0xc3 ary
stack
=> val

expandarray_SC_xx_xx

スタックトップのオブジェクトが配列であれば、それを展開する。

instruction sequence
0xc4 num flag
stack
... ary => ...

expandarray_SC_ax_xx

スタックトップのオブジェクトが配列であれば、それを展開する。

instruction sequence
0xc5 num flag
stack
... ary => ...

expandarray_SC_bx_xx

スタックトップのオブジェクトが配列であれば、それを展開する。

instruction sequence
0xc6 num flag
stack
... ary => ...

expandarray_SC_ab_xx

スタックトップのオブジェクトが配列であれば、それを展開する。

instruction sequence
0xc7 num flag
stack
... ary => ...

expandarray_SC_ba_xx

スタックトップのオブジェクトが配列であれば、それを展開する。

instruction sequence
0xc8 num flag
stack
... ary => ...

newhash_SC_xx_ax

Hash.new

instruction sequence
0xc9 num
stack
... => val

newhash_SC_ax_ax

Hash.new

instruction sequence
0xca num
stack
... => val

newhash_SC_bx_ax

Hash.new

instruction sequence
0xcb num
stack
... => val

newhash_SC_ab_ax

Hash.new

instruction sequence
0xcc num
stack
... => val

newhash_SC_ba_ax

Hash.new

instruction sequence
0xcd num
stack
... => val

newrange_SC_xx_ax

Range.new(low, high, flag) のようなオブジェクトを置く。

instruction sequence
0xce flag
stack
low high => val

newrange_SC_ax_ax

Range.new(low, high, flag) のようなオブジェクトを置く。

instruction sequence
0xcf flag
stack
low high => val

newrange_SC_bx_ax

Range.new(low, high, flag) のようなオブジェクトを置く。

instruction sequence
0xd0 flag
stack
low high => val

newrange_SC_ab_ax

Range.new(low, high, flag) のようなオブジェクトを置く。

instruction sequence
0xd1 flag
stack
low high => val

newrange_SC_ba_ax

Range.new(low, high, flag) のようなオブジェクトを置く。

instruction sequence
0xd2 flag
stack
low high => val

putnot_SC_xx_ax

!val であるオブジェクトを置く。

instruction sequence
0xd3
stack
obj => val

putnot_SC_ax_ax

!val であるオブジェクトを置く。

instruction sequence
0xd4
stack
obj => val

putnot_SC_bx_ax

!val であるオブジェクトを置く。

instruction sequence
0xd5
stack
obj => val

putnot_SC_ab_ab

!val であるオブジェクトを置く。

instruction sequence
0xd6
stack
obj => val

putnot_SC_ba_ba

!val であるオブジェクトを置く。

instruction sequence
0xd7
stack
obj => val

pop_SC_xx_xx

スタックから一つポップする。

instruction sequence
0xd8
stack
val =>

pop_SC_ax_xx

スタックから一つポップする。

instruction sequence
0xd9
stack
val =>

pop_SC_bx_xx

スタックから一つポップする。

instruction sequence
0xda
stack
val =>

pop_SC_ab_ax

スタックから一つポップする。

instruction sequence
0xdb
stack
val =>

pop_SC_ba_bx

スタックから一つポップする。

instruction sequence
0xdc
stack
val =>

dup_SC_xx_ab

スタックトップをコピーしてスタックにおく

instruction sequence
0xdd
stack
val => val2 val1

dup_SC_ax_ab

スタックトップをコピーしてスタックにおく

instruction sequence
0xde
stack
val => val2 val1

dup_SC_bx_ab

スタックトップをコピーしてスタックにおく

instruction sequence
0xdf
stack
val => val2 val1

dup_SC_ab_ba

スタックトップをコピーしてスタックにおく

instruction sequence
0xe0
stack
val => val2 val1

dup_SC_ba_ab

スタックトップをコピーしてスタックにおく

instruction sequence
0xe1
stack
val => val2 val1

dupn_SC_xx_xx

スタックトップから n 個をコピーしてスタックにおく

instruction sequence
0xe2 n
stack
... => ...

dupn_SC_ax_xx

スタックトップから n 個をコピーしてスタックにおく

instruction sequence
0xe3 n
stack
... => ...

dupn_SC_bx_xx

スタックトップから n 個をコピーしてスタックにおく

instruction sequence
0xe4 n
stack
... => ...

dupn_SC_ab_xx

スタックトップから n 個をコピーしてスタックにおく

instruction sequence
0xe5 n
stack
... => ...

dupn_SC_ba_xx

スタックトップから n 個をコピーしてスタックにおく

instruction sequence
0xe6 n
stack
... => ...

swap_SC_xx_ab

スタックトップの2つを交換する。

instruction sequence
0xe7
stack
val obj => val obj

swap_SC_ax_ab

スタックトップの2つを交換する。

instruction sequence
0xe8
stack
val obj => val obj

swap_SC_bx_ab

スタックトップの2つを交換する。

instruction sequence
0xe9
stack
val obj => val obj

swap_SC_ab_ab

スタックトップの2つを交換する。

instruction sequence
0xea
stack
val obj => val obj

swap_SC_ba_ab

スタックトップの2つを交換する。

instruction sequence
0xeb
stack
val obj => val obj

reput_SC_xx_ax

instruction sequence
0xec
stack
... val => val

reput_SC_ax_ax

instruction sequence
0xed
stack
... val => val

reput_SC_bx_ax

instruction sequence
0xee
stack
... val => val

reput_SC_ab_ax

instruction sequence
0xef
stack
... val => val

reput_SC_ba_ax

instruction sequence
0xf0
stack
... val => val

topn_SC_xx_ax

スタックトップから n 個目をスタックトップにコピー

instruction sequence
0xf1 n
stack
... => val

topn_SC_ax_ax

スタックトップから n 個目をスタックトップにコピー

instruction sequence
0xf2 n
stack
... => val

topn_SC_bx_ax

スタックトップから n 個目をスタックトップにコピー

instruction sequence
0xf3 n
stack
... => val

topn_SC_ab_ax

スタックトップから n 個目をスタックトップにコピー

instruction sequence
0xf4 n
stack
... => val

topn_SC_ba_ax

スタックトップから n 個目をスタックトップにコピー

instruction sequence
0xf5 n
stack
... => val

methoddef_SC_xx_xx

メソッド m を body として定義する。

instruction sequence
0xf6 id body
stack
=>

methoddef_SC_ax_ax

メソッド m を body として定義する。

instruction sequence
0xf7 id body
stack
=>

methoddef_SC_bx_bx

メソッド m を body として定義する。

instruction sequence
0xf8 id body
stack
=>

methoddef_SC_ab_ab

メソッド m を body として定義する。

instruction sequence
0xf9 id body
stack
=>

methoddef_SC_ba_ba

メソッド m を body として定義する。

instruction sequence
0xfa id body
stack
=>

singletonmethoddef_SC_xx_xx

特異メソッド m を body として obj に定義する。

instruction sequence
0xfb id body
stack
obj =>

singletonmethoddef_SC_ax_xx

特異メソッド m を body として obj に定義する。

instruction sequence
0xfc id body
stack
obj =>

singletonmethoddef_SC_bx_xx

特異メソッド m を body として obj に定義する。

instruction sequence
0xfd id body
stack
obj =>

singletonmethoddef_SC_ab_ax

特異メソッド m を body として obj に定義する。

instruction sequence
0xfe id body
stack
obj =>

singletonmethoddef_SC_ba_bx

特異メソッド m を body として obj に定義する。

instruction sequence
0xff id body
stack
obj =>

alias_SC_xx_xx

alias を作る。もし v_p が Qtrue なら、valias (global variable) を作る

instruction sequence
0x100 v_p id1 id2
stack
=>

alias_SC_ax_ax

alias を作る。もし v_p が Qtrue なら、valias (global variable) を作る

instruction sequence
0x101 v_p id1 id2
stack
=>

alias_SC_bx_bx

alias を作る。もし v_p が Qtrue なら、valias (global variable) を作る

instruction sequence
0x102 v_p id1 id2
stack
=>

alias_SC_ab_ab

alias を作る。もし v_p が Qtrue なら、valias (global variable) を作る

instruction sequence
0x103 v_p id1 id2
stack
=>

alias_SC_ba_ba

alias を作る。もし v_p が Qtrue なら、valias (global variable) を作る

instruction sequence
0x104 v_p id1 id2
stack
=>

undef_SC_xx_xx

undef

instruction sequence
0x105 id
stack
=>

undef_SC_ax_ax

undef

instruction sequence
0x106 id
stack
=>

undef_SC_bx_bx

undef

instruction sequence
0x107 id
stack
=>

undef_SC_ab_ab

undef

instruction sequence
0x108 id
stack
=>

undef_SC_ba_ba

undef

instruction sequence
0x109 id
stack
=>

defined_SC_xx_ax

defined?

instruction sequence
0x10a type obj needstr
stack
... => val

defined_SC_ax_ax

defined?

instruction sequence
0x10b type obj needstr
stack
... => val

defined_SC_bx_ax

defined?

instruction sequence
0x10c type obj needstr
stack
... => val

defined_SC_ab_ax

defined?

instruction sequence
0x10d type obj needstr
stack
... => val

defined_SC_ba_ax

defined?

instruction sequence
0x10e type obj needstr
stack
... => val

classdef_SC_xx_ax

instruction sequence
0x10f id klass_iseq
stack
cbase super => val

classdef_SC_ax_ax

instruction sequence
0x110 id klass_iseq
stack
cbase super => val

classdef_SC_bx_ax

instruction sequence
0x111 id klass_iseq
stack
cbase super => val

classdef_SC_ab_ax

instruction sequence
0x112 id klass_iseq
stack
cbase super => val

classdef_SC_ba_ax

instruction sequence
0x113 id klass_iseq
stack
cbase super => val

singletonclassdef_SC_xx_ax

特異クラス定義スコープへ移行する。

instruction sequence
0x114 sclass_iseq
stack
obj => val

singletonclassdef_SC_ax_ax

特異クラス定義スコープへ移行する。

instruction sequence
0x115 sclass_iseq
stack
obj => val

singletonclassdef_SC_bx_ax

特異クラス定義スコープへ移行する。

instruction sequence
0x116 sclass_iseq
stack
obj => val

singletonclassdef_SC_ab_ab

特異クラス定義スコープへ移行する。

instruction sequence
0x117 sclass_iseq
stack
obj => val

singletonclassdef_SC_ba_ba

特異クラス定義スコープへ移行する。

instruction sequence
0x118 sclass_iseq
stack
obj => val

moduledef_SC_xx_ax

モジュール定義スコープへ移行する。

instruction sequence
0x119 id module_iseq
stack
mbase => val

moduledef_SC_ax_ax

モジュール定義スコープへ移行する。

instruction sequence
0x11a id module_iseq
stack
mbase => val

moduledef_SC_bx_ax

モジュール定義スコープへ移行する。

instruction sequence
0x11b id module_iseq
stack
mbase => val

moduledef_SC_ab_ax

モジュール定義スコープへ移行する。

instruction sequence
0x11c id module_iseq
stack
mbase => val

moduledef_SC_ba_ax

モジュール定義スコープへ移行する。

instruction sequence
0x11d id module_iseq
stack
mbase => val

popcref_SC_xx_xx

クラスのネスト関係情報をひとつポップする

instruction sequence
0x11e
stack
=>

popcref_SC_ax_ax

クラスのネスト関係情報をひとつポップする

instruction sequence
0x11f
stack
=>

popcref_SC_bx_bx

クラスのネスト関係情報をひとつポップする

instruction sequence
0x120
stack
=>

popcref_SC_ab_ab

クラスのネスト関係情報をひとつポップする

instruction sequence
0x121
stack
=>

popcref_SC_ba_ba

クラスのネスト関係情報をひとつポップする

instruction sequence
0x122
stack
=>

send_SC_xx_ax

obj.send(id, args) # args.size => num

instruction sequence
0x123 id argc block flag ic
stack
... => val

send_SC_ax_ax

obj.send(id, args) # args.size => num

instruction sequence
0x124 id argc block flag ic
stack
... => val

send_SC_bx_ax

obj.send(id, args) # args.size => num

instruction sequence
0x125 id argc block flag ic
stack
... => val

send_SC_ab_ax

obj.send(id, args) # args.size => num

instruction sequence
0x126 id argc block flag ic
stack
... => val

send_SC_ba_ax

obj.send(id, args) # args.size => num

instruction sequence
0x127 id argc block flag ic
stack
... => val

super_SC_xx_ax

super(args) # args.size => num

instruction sequence
0x128 num flag
stack
... => val

super_SC_ax_ax

super(args) # args.size => num

instruction sequence
0x129 num flag
stack
... => val

super_SC_bx_ax

super(args) # args.size => num

instruction sequence
0x12a num flag
stack
... => val

super_SC_ab_ax

super(args) # args.size => num

instruction sequence
0x12b num flag
stack
... => val

super_SC_ba_ax

super(args) # args.size => num

instruction sequence
0x12c num flag
stack
... => val

zsuper_SC_xx_ax

super

instruction sequence
0x12d
stack
... => val

zsuper_SC_ax_ax

super

instruction sequence
0x12e
stack
... => val

zsuper_SC_bx_ax

super

instruction sequence
0x12f
stack
... => val

zsuper_SC_ab_ax

super

instruction sequence
0x130
stack
... => val

zsuper_SC_ba_ax

super

instruction sequence
0x131
stack
... => val

yield_SC_xx_ax

yield(args) # args.size => num

instruction sequence
0x132 num flag
stack
... => val

yield_SC_ax_ax

yield(args) # args.size => num

instruction sequence
0x133 num flag
stack
... => val

yield_SC_bx_ax

yield(args) # args.size => num

instruction sequence
0x134 num flag
stack
... => val

yield_SC_ab_ax

yield(args) # args.size => num

instruction sequence
0x135 num flag
stack
... => val

yield_SC_ba_ax

yield(args) # args.size => num

instruction sequence
0x136 num flag
stack
... => val

end_SC_xx_ax

このスコープから抜ける。

instruction sequence
0x137 idx
stack
val => val

end_SC_ax_ax

このスコープから抜ける。

instruction sequence
0x138 idx
stack
val => val

end_SC_bx_ax

このスコープから抜ける。

instruction sequence
0x139 idx
stack
val => val

end_SC_ab_ax

このスコープから抜ける。

instruction sequence
0x13a idx
stack
val => val

end_SC_ba_ax

このスコープから抜ける。

instruction sequence
0x13b idx
stack
val => val

throw_SC_xx_xx

longjump

instruction sequence
0x13c throw_state
stack
throwobj =>

throw_SC_ax_xx

longjump

instruction sequence
0x13d throw_state
stack
throwobj =>

throw_SC_bx_xx

longjump

instruction sequence
0x13e throw_state
stack
throwobj =>

throw_SC_ab_ax

longjump

instruction sequence
0x13f throw_state
stack
throwobj =>

throw_SC_ba_bx

longjump

instruction sequence
0x140 throw_state
stack
throwobj =>

jump_SC_xx_xx

PC を (PC + dst) にする。

instruction sequence
0x141 dst
stack
=>

jump_SC_ax_ax

PC を (PC + dst) にする。

instruction sequence
0x142 dst
stack
=>

jump_SC_bx_bx

PC を (PC + dst) にする。

instruction sequence
0x143 dst
stack
=>

jump_SC_ab_ab

PC を (PC + dst) にする。

instruction sequence
0x144 dst
stack
=>

jump_SC_ba_ba

PC を (PC + dst) にする。

instruction sequence
0x145 dst
stack
=>

if_SC_xx_xx

もし val が false か nil でなければ、PC を (PC + dst) にする。

instruction sequence
0x146 dst
stack
val =>

if_SC_ax_xx

もし val が false か nil でなければ、PC を (PC + dst) にする。

instruction sequence
0x147 dst
stack
val =>

if_SC_bx_xx

もし val が false か nil でなければ、PC を (PC + dst) にする。

instruction sequence
0x148 dst
stack
val =>

if_SC_ab_ax

もし val が false か nil でなければ、PC を (PC + dst) にする。

instruction sequence
0x149 dst
stack
val =>

if_SC_ba_bx

もし val が false か nil でなければ、PC を (PC + dst) にする。

instruction sequence
0x14a dst
stack
val =>

unless_SC_xx_xx

もし val が false か nil ならば、PC を (PC + dst) にする。

instruction sequence
0x14b dst
stack
val =>

unless_SC_ax_xx

もし val が false か nil ならば、PC を (PC + dst) にする。

instruction sequence
0x14c dst
stack
val =>

unless_SC_bx_xx

もし val が false か nil ならば、PC を (PC + dst) にする。

instruction sequence
0x14d dst
stack
val =>

unless_SC_ab_ax

もし val が false か nil ならば、PC を (PC + dst) にする。

instruction sequence
0x14e dst
stack
val =>

unless_SC_ba_bx

もし val が false か nil ならば、PC を (PC + dst) にする。

instruction sequence
0x14f dst
stack
val =>

getinlinecache_SC_xx_ax

inline cache

instruction sequence
0x150 ic dst
stack
=> val

getinlinecache_SC_ax_ab

inline cache

instruction sequence
0x151 ic dst
stack
=> val

getinlinecache_SC_bx_ba

inline cache

instruction sequence
0x152 ic dst
stack
=> val

getinlinecache_SC_ab_ba

inline cache

instruction sequence
0x153 ic dst
stack
=> val

getinlinecache_SC_ba_ab

inline cache

instruction sequence
0x154 ic dst
stack
=> val

setinlinecache_SC_xx_ax

set inline cahce

instruction sequence
0x155 dst
stack
val => val

setinlinecache_SC_ax_ax

set inline cahce

instruction sequence
0x156 dst
stack
val => val

setinlinecache_SC_bx_ax

set inline cahce

instruction sequence
0x157 dst
stack
val => val

setinlinecache_SC_ab_ab

set inline cahce

instruction sequence
0x158 dst
stack
val => val

setinlinecache_SC_ba_ba

set inline cahce

instruction sequence
0x159 dst
stack
val => val

opt_plus_SC_xx_ax

最適化された X+Y。

instruction sequence
0x15a
stack
recv obj => val

opt_plus_SC_ax_ax

最適化された X+Y。

instruction sequence
0x15b
stack
recv obj => val

opt_plus_SC_bx_ax

最適化された X+Y。

instruction sequence
0x15c
stack
recv obj => val

opt_plus_SC_ab_ax

最適化された X+Y。

instruction sequence
0x15d
stack
recv obj => val

opt_plus_SC_ba_ax

最適化された X+Y。

instruction sequence
0x15e
stack
recv obj => val

opt_minus_SC_xx_ax

最適化された X-Y。

instruction sequence
0x15f
stack
recv obj => val

opt_minus_SC_ax_ax

最適化された X-Y。

instruction sequence
0x160
stack
recv obj => val

opt_minus_SC_bx_ax

最適化された X-Y。

instruction sequence
0x161
stack
recv obj => val

opt_minus_SC_ab_ax

最適化された X-Y。

instruction sequence
0x162
stack
recv obj => val

opt_minus_SC_ba_ax

最適化された X-Y。

instruction sequence
0x163
stack
recv obj => val

opt_lt_SC_xx_ax

最適化された X<Y。

instruction sequence
0x164
stack
recv obj => val

opt_lt_SC_ax_ax

最適化された X<Y。

instruction sequence
0x165
stack
recv obj => val

opt_lt_SC_bx_ax

最適化された X<Y。

instruction sequence
0x166
stack
recv obj => val

opt_lt_SC_ab_ax

最適化された X<Y。

instruction sequence
0x167
stack
recv obj => val

opt_lt_SC_ba_ax

最適化された X<Y。

instruction sequence
0x168
stack
recv obj => val

opt_ltlt_SC_xx_ax

<<

instruction sequence
0x169
stack
recv obj => val

opt_ltlt_SC_ax_ax

<<

instruction sequence
0x16a
stack
recv obj => val

opt_ltlt_SC_bx_ax

<<

instruction sequence
0x16b
stack
recv obj => val

opt_ltlt_SC_ab_ax

<<

instruction sequence
0x16c
stack
recv obj => val

opt_ltlt_SC_ba_ax

<<

instruction sequence
0x16d
stack
recv obj => val

opt_regexpmatch1_SC_xx_ax

最適化された正規表現マッチ

instruction sequence
0x16e r
stack
obj => val

opt_regexpmatch1_SC_ax_ax

最適化された正規表現マッチ

instruction sequence
0x16f r
stack
obj => val

opt_regexpmatch1_SC_bx_ax

最適化された正規表現マッチ

instruction sequence
0x170 r
stack
obj => val

opt_regexpmatch1_SC_ab_ab

最適化された正規表現マッチ

instruction sequence
0x171 r
stack
obj => val

opt_regexpmatch1_SC_ba_ba

最適化された正規表現マッチ

instruction sequence
0x172 r
stack
obj => val

opt_regexpmatch2_SC_xx_ax

最適化された正規表現マッチ 2

instruction sequence
0x173
stack
obj2 obj1 => val

opt_regexpmatch2_SC_ax_ax

最適化された正規表現マッチ 2

instruction sequence
0x174
stack
obj2 obj1 => val

opt_regexpmatch2_SC_bx_ax

最適化された正規表現マッチ 2

instruction sequence
0x175
stack
obj2 obj1 => val

opt_regexpmatch2_SC_ab_ax

最適化された正規表現マッチ 2

instruction sequence
0x176
stack
obj2 obj1 => val

opt_regexpmatch2_SC_ba_ax

最適化された正規表現マッチ 2

instruction sequence
0x177
stack
obj2 obj1 => val

opt_call_native_compiled_SC_xx_xx

ネイティブコンパイルしたメソッドを kick

instruction sequence
0x178
stack
=>

opt_call_native_compiled_SC_ax_ax

ネイティブコンパイルしたメソッドを kick

instruction sequence
0x179
stack
=>

opt_call_native_compiled_SC_bx_bx

ネイティブコンパイルしたメソッドを kick

instruction sequence
0x17a
stack
=>

opt_call_native_compiled_SC_ab_ab

ネイティブコンパイルしたメソッドを kick

instruction sequence
0x17b
stack
=>

opt_call_native_compiled_SC_ba_ba

ネイティブコンパイルしたメソッドを kick

instruction sequence
0x17c
stack
=>

getlocal_OP_1_SC_xx_ax

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x17d
stack
=> val

getlocal_OP_1_SC_ax_ab

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x17e
stack
=> val

getlocal_OP_1_SC_bx_ba

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x17f
stack
=> val

getlocal_OP_1_SC_ab_ba

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x180
stack
=> val

getlocal_OP_1_SC_ba_ab

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x181
stack
=> val

setlocal_OP_1_SC_xx_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x182
stack
val =>

setlocal_OP_1_SC_ax_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x183
stack
val =>

setlocal_OP_1_SC_bx_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x184
stack
val =>

setlocal_OP_1_SC_ab_ax

idx で指定されたローカル変数を val にする。

instruction sequence
0x185
stack
val =>

setlocal_OP_1_SC_ba_bx

idx で指定されたローカル変数を val にする。

instruction sequence
0x186
stack
val =>

getlocal_OP_2_SC_xx_ax

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x187
stack
=> val

getlocal_OP_2_SC_ax_ab

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x188
stack
=> val

getlocal_OP_2_SC_bx_ba

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x189
stack
=> val

getlocal_OP_2_SC_ab_ba

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x18a
stack
=> val

getlocal_OP_2_SC_ba_ab

idx で指定されたローカル変数をスタックに置く。

instruction sequence
0x18b
stack
=> val

setlocal_OP_2_SC_xx_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x18c
stack
val =>

setlocal_OP_2_SC_ax_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x18d
stack
val =>

setlocal_OP_2_SC_bx_xx

idx で指定されたローカル変数を val にする。

instruction sequence
0x18e
stack
val =>

setlocal_OP_2_SC_ab_ax

idx で指定されたローカル変数を val にする。

instruction sequence
0x18f
stack
val =>

setlocal_OP_2_SC_ba_bx

idx で指定されたローカル変数を val にする。

instruction sequence
0x190
stack
val =>

getdynamic_OP__WC__0_SC_xx_ax

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x191 idx
stack
=> val

getdynamic_OP__WC__0_SC_ax_ab

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x192 idx
stack
=> val

getdynamic_OP__WC__0_SC_bx_ba

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x193 idx
stack
=> val

getdynamic_OP__WC__0_SC_ab_ba

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x194 idx
stack
=> val

getdynamic_OP__WC__0_SC_ba_ab

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x195 idx
stack
=> val

getdynamic_OP_1_0_SC_xx_ax

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x196
stack
=> val

getdynamic_OP_1_0_SC_ax_ab

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x197
stack
=> val

getdynamic_OP_1_0_SC_bx_ba

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x198
stack
=> val

getdynamic_OP_1_0_SC_ab_ba

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x199
stack
=> val

getdynamic_OP_1_0_SC_ba_ab

level, idx で指定されたブロックローカル変数の値をスタックに置く。

instruction sequence
0x19a
stack
=> val

putobject_OP_INT2FIX_O_0_C__SC_xx_ax

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x19b
stack
=> val

putobject_OP_INT2FIX_O_0_C__SC_ax_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x19c
stack
=> val

putobject_OP_INT2FIX_O_0_C__SC_bx_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x19d
stack
=> val

putobject_OP_INT2FIX_O_0_C__SC_ab_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x19e
stack
=> val

putobject_OP_INT2FIX_O_0_C__SC_ba_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x19f
stack
=> val

putobject_OP_INT2FIX_O_1_C__SC_xx_ax

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a0
stack
=> val

putobject_OP_INT2FIX_O_1_C__SC_ax_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a1
stack
=> val

putobject_OP_INT2FIX_O_1_C__SC_bx_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a2
stack
=> val

putobject_OP_INT2FIX_O_1_C__SC_ab_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a3
stack
=> val

putobject_OP_INT2FIX_O_1_C__SC_ba_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a4
stack
=> val

putobject_OP_Qtrue_SC_xx_ax

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a5
stack
=> val

putobject_OP_Qtrue_SC_ax_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a6
stack
=> val

putobject_OP_Qtrue_SC_bx_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a7
stack
=> val

putobject_OP_Qtrue_SC_ab_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a8
stack
=> val

putobject_OP_Qtrue_SC_ba_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1a9
stack
=> val

putobject_OP_Qfalse_SC_xx_ax

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1aa
stack
=> val

putobject_OP_Qfalse_SC_ax_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1ab
stack
=> val

putobject_OP_Qfalse_SC_bx_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1ac
stack
=> val

putobject_OP_Qfalse_SC_ab_ba

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1ad
stack
=> val

putobject_OP_Qfalse_SC_ba_ab

オブジェクトを置く。i.e. Fixnum, true, false, nil, and so on.

instruction sequence
0x1ae
stack
=> val

send_OP__WC___WC__Qfalse_0__WC__SC_xx_ax

obj.send(id, args) # args.size => num

instruction sequence
0x1af id argc ic
stack
... => val

send_OP__WC___WC__Qfalse_0__WC__SC_ax_ax

obj.send(id, args) # args.size => num

instruction sequence
0x1b0 id argc ic
stack
... => val

send_OP__WC___WC__Qfalse_0__WC__SC_bx_ax

obj.send(id, args) # args.size => num

instruction sequence
0x1b1 id argc ic
stack
... => val

send_OP__WC___WC__Qfalse_0__WC__SC_ab_ax

obj.send(id, args) # args.size => num

instruction sequence
0x1b2 id argc ic
stack
... => val

send_OP__WC___WC__Qfalse_0__WC__SC_ba_ax

obj.send(id, args) # args.size => num

instruction sequence
0x1b3 id argc ic
stack
... => val

UNIFIED_putobject_putobject_SC_xx_ab

unified insn

instruction sequence
0x1b4 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putobject_SC_ax_ba

unified insn

instruction sequence
0x1b5 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putobject_SC_bx_ab

unified insn

instruction sequence
0x1b6 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putobject_SC_ab_ab

unified insn

instruction sequence
0x1b7 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putobject_SC_ba_ba

unified insn

instruction sequence
0x1b8 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putstring_SC_xx_ab

unified insn

instruction sequence
0x1b9 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putstring_SC_ax_ba

unified insn

instruction sequence
0x1ba val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putstring_SC_bx_ab

unified insn

instruction sequence
0x1bb val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putstring_SC_ab_ab

unified insn

instruction sequence
0x1bc val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putstring_SC_ba_ba

unified insn

instruction sequence
0x1bd val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putobject_SC_xx_ab

unified insn

instruction sequence
0x1be val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putobject_SC_ax_ba

unified insn

instruction sequence
0x1bf val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putobject_SC_bx_ab

unified insn

instruction sequence
0x1c0 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putobject_SC_ab_ab

unified insn

instruction sequence
0x1c1 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putstring_putobject_SC_ba_ba

unified insn

instruction sequence
0x1c2 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putstring_SC_xx_ab

unified insn

instruction sequence
0x1c3 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putstring_SC_ax_ba

unified insn

instruction sequence
0x1c4 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putstring_SC_bx_ab

unified insn

instruction sequence
0x1c5 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putstring_SC_ab_ab

unified insn

instruction sequence
0x1c6 val_0 val_1
stack
=> val_1 val_0

UNIFIED_putobject_putstring_SC_ba_ba

unified insn

instruction sequence
0x1c7 val_0 val_1
stack
=> val_1 val_0

その他

テスト

test/test_* がテストケースです。一応、ミスなく動くはずです。逆にいうと、 このテストに記述されている例ではきちんと動作するということです。

ベンチマーク

benchmark/bm_* にベンチマークプログラムがおいてあります。

今後の予定

まだまだやらなければいけないこと、未実装部分がたくさんありますんでやって いかなければなりません。一番大きな目標は eval.c を置き換えることでしょう か。

Verifier

YARV 命令列は、ミスがあっても動かしてしまうため危険である可能性がありま す。そのため、スタックの利用状態をきちんと事前に検証するようなベリファイ アを用意しなければならないと考えています。

Compiled File の構想

Ruby プログラムをこの命令セットにシリアライズしたデータ構造をファイルに 出力できるようにしたいと考えています。これを利用して一度コンパイルした命 令列をファイルに保存しておけば、次回ロード時にはコンパイルの手間、コスト を省くことができます。

全体構成

次のようなファイル構成を考えていますが、まだ未定です。

u4 : 4 byte unsigned storage
u2 : 2 byte unsigned storage
u1 : 1 byte unsigned storage

every storages are little endian :-)

CompiledFile{
  u4 magic;

  u2 major;
  u2 minor;

  u4 character_code;

  u4 constants_pool_count;
  ConstantEntry constants_pool[constants_pool_count];

  u4 block_count;
  blockEntry blocks[block_count];

  u4 method_count;
  MethodEntry methods[method_count];
}

Java classfile のパクリ。