おそらくVMMakerを見たいと思うでしょう。その Interpreter クラスは CompiledMethod のバイトコードを実行し、実際にメッセージをオブジェクトに送信します。
たとえば、Object>>respondsTo: のバイトコードを見ると、
17 <70> self
18 <C7> send: class
19 <10> pushTemp: 0
20 <E0> send: canUnderstand:
21 <7C> returnTop
Interpreter はバイトコードを読み取り、そのバイトコードをその BytecodeTable (Interpreter class>>initialiseBytecodeTable で初期化) で検索し、適切なメソッドを実行します。<70> (#pushReceiverByteCode) は、自己をインタープリターの内部スタックにプッシュします。次に、(#bytecodePrimClass) は「自分のクラスを見つける」に要約されます。<10> (#pushTemporaryVariableBytecode) は #respondsTo: への引数をスタックにプッシュします。興味深い部分は (#sendLiteralSelectorBytecode) で発生し、これは を呼び出しますself normalSend
。#normalSend は、レシーバーのクラス (この場合) を判別し、実行しようとしている実際のメソッドを見つけて実行する をself class
呼び出します。self commonSend
私は VM 初心者です。上記は、アルゴリズムの動作などを確認するのに最適な場所ではないかもしれませんが (または最良の説明でさえ)、開始するのに適した場所であることを願っています。
VM が実際にメッセージを送信するために使用するアルゴリズムは、質問で概説したとおりです。そのアルゴリズムの実際の実装は で定義されていInterpreter>>commonSend
ます。検索アルゴリズムは にInterpreter>>lookupMethodInClass:
あり、実行アルゴリズムは にありInterpreter>>internalExecuteNewMethod
ます。
前者は、あなたが説明するように機能します:
- リスト項目
- このクラスでメソッドを見つけてみてください。
- 見つからない場合は、スーパークラスを調べます。
- これが再帰的に失敗する場合は、find #doesNotUnderstand を試してください。
- #doesNotUnderstand: がクラス階層のどこにも存在しない場合は、エラーをスローします。
後者は次のように機能します。
- プリミティブの場合は、プリミティブを実行します。
- そうでない場合は、新しい方法をアクティブ化します (新しいアクティブ化レコードを作成します)。
- (割り込みをチェックしてください。)