VisualWorks:バイトコードセット
2007/03/30 (Fri) 22:07:46 JST
このページはVisualWorks 5i を参考にしています。
http://smalltalk.cincom.com/prodinformation/Vw5iByteCodes.htm
各バイトを次のように略しています。
- BC - オペコード
- B1 - 1バイト目
- B2 - 2バイト目
文中特に説明のない「インデックス」は、スタック上のローカル変数(メソッド中の一時変数ではありません)のインデックスを指します。「インスタンス変数のインデックス」とは、レシーバのインスタンス変数のことを指します。VisualWorksのオブジェクトはインスタンス変数を配列で管理しています。
1バイトコード
ロード
?OpLoadInst (16r00-16rFF (16))
インデックスがBCのインスタンス変数をスタックに積みます。
?OpLoadTemp (16r10-16r1B (12))
インデックスが「BC - 16r10 (0-11)」のローカル変数をスタックに積みます。
?OpLoadLiteral (16r1C-16r2B (16))
インデックスが「BC - 16r1C (0-15)」のリテラルをスタックに積みます。VisualWorksのリテラルは不変です。
?OpLoadStatic (16r34-16r3F (12))
インデックスが「BC - 16r34 (0-11)」のリテラルに #value
のメッセージを送った結果を、スタックに積みます。
この命令は、クラスや名前空間などの参照を要するオブジェクトに対して使われます。これらのオブジェクトは参照(?DeferredBinding)リテラルとしてコンパイルされ、#value
を送ると参照先のオブジェクトを取得できます。
(16r1C-16r23 (8))
使われていません。
?OpNoOp (16r40)
何もしません。
(16r41)
使われていません。
(16r42)
現在は使われていませんが、ブレークポイント用のバイトコードとして予約されています。
?OpPrimReturn (16r43)
?OpLoadReceiver (16r44)
レシーバをスタックに積みます。
?OpPopLoadReceiver (16r45)
スタックの最後に積まれた値を取り除き、レシーバをスタックに積みます。戻り値を省略した場合の、暗黙のselfを返すのに使われます。
?OpLoadNil (16r46)
nilをスタックに積みます。
?OpLoadTrue (16r47)
trueをスタックに積みます。
?OpLoadFalse (16r48)
falseをスタックに積みます。
?OpLoadZero (16r49-16r4B (3))
「BC-16r49」の整数(0/1/2)をスタックに積みます。
?OpStorePopTemp (16r4C-16r53 (8))
スタックの最後に積まれた値を取り除き、その値をインデックスが「BC-16r4C (0-8)」のローカル変数に代入します。代入式などで使われます。
?OpLoadThisContext (16r54)
現在のコンテキストをスタックに積みます。
(16r55)
使われていません。
?OpPopLoadTemp (16r56-16r57 (2))
スタックの最後に積まれた値を取り除き、インデックスが「BC-16r56 (0-1)」のローカル変数をスタックに積みます。
?OpStorePopInst (16r58-16r5F (8))
スタックの最後に積まれた値を取り除き、その値をインデックスが「BC-16r4C (0-8)」のインスタンス変数に代入します。
その他
?OpReturnReceiver (16r60)
レシーバを戻り値としてメソッドブロックを抜けます。
(16r61)
使われていません。
?OpReturnNil (16r62)
nilを戻り値としてメソッドブロックを抜けます。
?OpReturnTrue (16r63)
trueを戻り値としてメソッドブロックを抜けます。
?OpReturnFalse (16r64)
falseを戻り値としてメソッドブロックを抜けます。
?OpReturn (16r65)
スタックの最上部の値を戻り値としてメソッドブロックを抜けます。
?OpPop (16r66)
スタックの最上部の値を取り除きます。
?OpLoopHead (16r67)
?OpDupFirst (16r68)
?OpDupNext (16r69)
?OpNoDup (16r6A)
?OpSends (16r70-16r97 (40))
引数を 0-2 個受けとるメッセージ送信。引数ごとに 16, 16, 8 の計40個のバイトコードが用意されていて、BCがリテラルのセレクタのインデックスを指定します。例えば <82> なら、スタックから引数を1つポップし、リテラルの3番目にあるセレクタでメッセージを送信することになります。
- 単項メッセージ: 16r70-16r7F (16)
- 引数が1つのメッセージ: 16r80-16r8F (16)
- 引数が2つのメッセージ: 16r90-16r97 (8)
?OpSendSelf0 (16r98-16r9F (8))
selfに引数をとらないメッセージを送信します。セレクタはリテラルのBC-16r98番目のものを使います。
制御
2バイトコード
その他
?OpXNoCheckSend (16rCC)
コンパイル時にレシーバの型が判明している場合(即値と一部のクラス)のメッセージ送信です。レシーバの型を判断できるのは、リテラルかselfにメッセージを送る場合です。スタックリテラルの「B1 / 32 の余り」番目にあるセレクタで、「B1 / 32 の商」個の引数を受け取るメッセージを送ります。
VisualWorksのオブジェクトにはクラスを表すフラグが入っており、次のクラスのインスタンスであるかどうかを高速に判別することができます。
これらのクラスに加えて、即値である?SmallIntegerとCharacterに対するメッセージも?NoCheckSendになります。
?OpXNonImmediateSend (16rCD)
レシーバが即値ではない、つまり?SmallIntegerでもCharacterでもないことが判明している場合のメッセージ送信です。スタックリテラルの「B1 / 32 の余り」番目にあるセレクタで、「B1 / 32 の商」個の引数を受け取るメッセージを送ります。
?OpXNonImmediateSend (16rCE)
基本的に?NoCheckSendと同じですが、セレクタは共有変数?SpecialSelectorsのB1番目のものを使います。
?OpXSend (16rF1)
スタックリテラルの「B1 / 32 の余り」番目にあるセレクタで、「B2 / 32」個の引数を受け取るメッセージを送ります。つまり1バイトのうち前半の4ビットで引数の数を、後半の4ビットでスタック上のインデックスを指定します。したがってバイトコードの表せる範囲は次のようになります。
- 引数が 0-6 個、インデックスが 0-31 の場合
- 引数 が 7 個、インデックスが 0 の場合
制御
?OpXNoCheckSpecialSend (16rDF)
基本的に?NoCheckSendと同じですが、セレクタは共有変数?SpecialSelectorsのB1番目のものを使います。
3バイトコード
?OpXXSend (16rFC)
スタック上の B2 番目にあるセレクタで、 B1 個の引数を受け取るメッセージを送ります。
4バイトコード
(16rFF)
予約されていますが、使われていません。
Inverse Pages: VisualWorks