4

Squeak でオブジェクトにメッセージを送信する場合、実行時の呼び出しアルゴリズムは次のようになります。

  1. curr <- 受信者のクラス
  2. curr が nil でない間繰り返す
    1. そのクラスのメソッドでセレクターを検索します。存在する場合は、それを呼び出して返します
    2. curr <- curr のスーパークラス
  3. 呼びかけるdoesNotUnderstand:_self

現在、非常によく似たアルゴリズムがメソッドに使用されており、実際にのコードrespondsTo:を調べることで確認できます。私が見つけようとしているのは、呼び出しに使用される上記のアルゴリズムのコードの場所ですrespondsTo:

同様のことを行うことは知っperform:ていますが、通常のメソッド呼び出しには使用されず、リフレクションのようなメソッド呼び出しメカニズムとしてのみ使用されると思います(たとえば、メソッド名がランタイムまでプログラマーにわからない場合)。

上記のコードもプリミティブ ディレクティブとして隠されている場合、プリミティブ呼び出しはどこにありますか? そうでない場合、コード自体はどこにありますか?

4

3 に答える 3

2

おそらく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ます。

前者は、あなたが説明するように機能します:

  1. リスト項目
  2. このクラスでメソッドを見つけてみてください。
  3. 見つからない場合は、スーパークラスを調べます。
  4. これが再帰的に失敗する場合は、find #doesNotUnderstand を試してください。
  5. #doesNotUnderstand: がクラス階層のどこにも存在しない場合は、エラーをスローします。

後者は次のように機能します。

  1. プリミティブの場合は、プリミティブを実行します。
  2. そうでない場合は、新しい方法をアクティブ化します (新しいアクティブ化レコードを作成します)。
  3. (割り込みをチェックしてください。)
于 2010-07-26T11:30:23.827 に答える
1

フランクの反応を理解するには、いくつかの背景情報が必要です。

コンパイラーは「バイトコードの送信」を生成します。これは後でVMのバイトコードインタープリターによって実行されます(またはjittedされますが、セマンティクスは同じです)。したがって、どのクラスでも実装を見つけることは期待できませんが、VMで見つけることができます。

他のほとんどのVMは、C、アセンブラー、またはその他の方法で記述されています...

ただし、squeak VMはSmalltalkで記述され、「Subset-of-Smalltalk-to-C-Compiler」(完全なSmalltalkセマンティクスをカバーしていないため「Slang」と呼ばれます)によってCにコンパイルされます。

Smalltalkで記述されているため、そのVMはもちろん、Squeak内から(イメージ内からイメージ上でSlang-interpreterを実行することにより)開発、デバッグ、およびテストできます。そのため、Frankが説明したように、Interpreterで実装を見つけることができます。

于 2010-08-25T11:55:31.287 に答える
1

さらに掘り下げると、ContextPartクラスはバイトコードを実行できるインタープリターです。そのドキュメントによると:

[この質問に関連するその方法] Smalltalk マシン自体の操作とまったく同じです

バイトコードの解釈方法を確認すると、

  1. そのinterpretメソッドはinterpretNextInstructionFor:for each 命令を呼び出します。
  2. interpretNextInstructionFor:send:super:numArgs:送信命令が発生したときに呼び出します。
  3. send:super:numArgs:呼び出しますsend:to:with:super:(プリミティブ メッセージではないと仮定します)。
  4. send:to:with:super:を使用して、使用する正しいセレクターを見つけますBehaviorlookupSelector:
  5. BehaviorlookupSelector:は、質問に表示されるアルゴリズムのスーパークラス ループを担当するものです。

したがって、これは私が探していた実際の実装ではありません (したがって、これは実際には答えではありません) が、正確なアルゴリズムのニュアンスを理解するのに役立つと思います。

于 2010-07-26T20:25:30.570 に答える