В Squeak, где я могу найти код для алгоритма обработки сообщений? - PullRequest
4 голосов
/ 26 июля 2010

При отправке сообщения объекту в Squeak алгоритм вызова во время выполнения выглядит примерно так:

  1. curr <- класс получателя </li>
  2. Повторите, пока curr не ноль
    1. Поиск селектора в методах этого класса; если он есть, вызовите его и верните
    2. curr <- суперкласс curr </li>
  3. Звоните doesNotUnderstand: на self

Теперь очень похожий алгоритм используется для метода respondsTo:, и действительно, это можно увидеть, изучив код respondsTo:. Я пытаюсь найти расположение кода для вышеуказанного алгоритма, используемого для вызова .

Я знаю, perform: делает что-то похожее, но я полагаю, что оно не используется для обычного вызова метода, а только как механизм вызова метода, похожего на отражение (например, когда имя метода не известно программисту до времени выполнения).

Если приведенный выше код также скрыт как примитивная директива, где бы я мог найти примитивный вызов? Если это не так, где бы я мог найти сам код?

Ответы [ 3 ]

2 голосов
/ 26 июля 2010

Возможно, вы захотите взглянуть на VMMaker . Его класс Interpreter - это парень, который выполняет байт-коды CompiledMethod и фактически отправляет сообщения вашим объектам.

Например, если вы посмотрите на байт-коды для Object >> RespondsTo: вы увидите

17 <70> self
18 <C7> send: class
19 <10> pushTemp: 0
20 <E0> send: canUnderstand:
21 <7C> returnTop

Интерпретатор читает байт-код, ищет этот байт-код в его BytecodeTable (инициализированном в классе интерпретатора >> initialiseBytecodeTable) и выполняет соответствующий метод. Поэтому <70> (#pushReceiverByteCode) помещает себя во внутренний стек интерпретатора. Затем (#bytecodePrimClass) сводится к «найти класс себя». <10> (#pushTeilitaryVariableBytecode) помещает аргумент в #respondsTo: в стек. Интересная часть происходит с (#sendLiteralSelectorBytecode), который вызывает self normalSend. #normalSend, в свою очередь, определяет класс получателя (в данном случае self class), а затем вызывает self commonSend, который находит фактический метод, который мы стремимся запустить, и затем запускает его.

Я новичок в ВМ; вышеприведенное может быть не лучшим местом, где можно увидеть алгоритм в действии и т. д. (или даже лучшим объяснением), но я надеюсь, что это хорошее место для начала.

Алгоритм, используемый виртуальной машиной для фактической отправки сообщения, описан в вашем вопросе. Фактическая реализация этого алгоритма определена в Interpreter>>commonSend. Алгоритм поиска в Interpreter>>lookupMethodInClass: и алгоритм выполнения в Interpreter>>internalExecuteNewMethod.

Первое работает так же, как вы описываете:

  1. Элемент списка
  2. Попробуйте найти метод в этом классе.
  3. Если не найдено, посмотрите в суперклассе.
  4. Если это не удается, попробуйте найти #doesNotUnderstand:
  5. Если #doesNotUnderstand: нигде в иерархии классов не существует, выведите ошибку.

Последний работает так:

  1. Если это примитив, запустите примитив.
  2. Если это не так, активируйте новый метод (создайте новую запись активации).
  3. (Проверьте на наличие прерываний.)
1 голос
/ 25 августа 2010

Чтобы понять ответ Фрэнкса, вам нужна некоторая справочная информация:

компилятор генерирует «байт-код отправки», который позже выполняется интерпретатором байт-кода виртуальной машины (или дублируется, но семантика та же).Таким образом, вы не ожидаете найти реализацию в каком-либо классе, но в виртуальной машине.

Большинство других виртуальных машин написаны на C, ассемблере или что-то еще ...

Однако: пискVM написана на Smalltalk и скомпилирована в C с помощью «Подмножества Smalltalk-to-C-Compiler» (так называемый «сленг», потому что она не охватывает полную семантику Smalltalk).

Будучи написанным на Smalltalk, эту ВМ можно, конечно, разрабатывать, отлаживать и тестировать из Squeak (запустив интерпретатор сленга на изображении изнутри изображения).Вот почему вы можете найти реализацию в интерпретаторе, как описано Фрэнком.

1 голос
/ 27 июля 2010

Еще копая, класс ContextPart является интерпретатором, способным запускать байт-код. Согласно его документации:

[методы, относящиеся к этому вопросу] точно параллельны работе самой машины Smalltalk .

Если мы проверим, как он интерпретирует байт-код,

  1. Его interpret метод вызывает его interpretNextInstructionFor: для каждой инструкции.
  2. interpretNextInstructionFor: вызывает send:super:numArgs: при обнаружении команды отправки.
  3. send:super:numArgs: вызывает send:to:with:super: (при условии, что это не примитивное сообщение).
  4. send:to:with:super: использует Behavior s lookupSelector:, чтобы найти правильный селектор для использования.
  5. Behavior '* lookupSelector: - это тот, кто отвечает за цикл суперкласса в алгоритме, указанном в вопросе.

Так что это , а не фактическая реализация, которую я искал (и, следовательно, это не совсем ответ), но я думаю, что это может помочь понять нюансы точного алгоритма.

...