4

在 Squeak 中向对象发送消息时,运行时调用算法类似于

  1. curr <- 接收者的类
  2. 在 curr 不为零时重复
    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

解释器读入一个字节码,在其 BytecodeTable 中查找该字节码(在解释器类>>initialiseBytecodeTable 中初始化)并执行适当的方法。所以 <70> (#pushReceiverByteCode) 将 self 推送到解释器的内部堆栈中。然后 (#bytecodePrimClass) 归结为“找到自己的班级”。<10> (#pushTemporaryVariableBytecode) 将参数推送到#respondsTo: 到堆栈上。有趣的部分发生在 (#sendLiteralSelectorBytecode),它调用self normalSend. #normalSend 依次计算出接收者的类(self class在这种情况下),然后调用self commonSend,它找到我们寻求运行的实际方法,然后运行它。

我是VM新手;以上可能不是查看算法运行等的绝对最佳位置(甚至不是最好的解释),但我希望这是一个很好的起点。

虚拟机用于实际发送消息的算法与您在问题中概述的一样。该算法的实际实现在Interpreter>>commonSend. 查找算法在里面Interpreter>>lookupMethodInClass:,执行算法在里面Interpreter>>internalExecuteNewMethod

前者的工作原理与您描述的一样:

  1. 项目清单
  2. 尝试在这个类中找到方法。
  3. 如果找不到,请查看超类。
  4. 如果递归失败,请尝试查找#doesNotUnderstand:
  5. 如果 #doesNotUnderstand: 在类层次结构中的任何位置都不存在,则抛出错误。

后者的工作方式如下:

  1. 如果是原语,则运行原语。
  2. 如果不是,请激活新方法(创建新的激活记录)。
  3. (检查中断。)
于 2010-07-26T11:30:23.827 回答
1

进一步挖掘,ContextPart该类是一个能够运行字节码的解释器。根据其文档:

[与此问题相关的方法]与 Smalltalk 机器本身的操作完全平行

如果我们检查它如何解释字节码,

  1. 它的interpret方法为每条指令调用它interpretNextInstructionFor:
  2. interpretNextInstructionFor:send:super:numArgs:遇到发送指令时调用。
  3. send:super:numArgs:调用send:to:with:super:(假设它不是原始消息)。
  4. send:to:with:super:使用Behavior'slookupSelector:来定位要使用的正确选择器。
  5. Behavior'slookupSelector:负责问题中出现的算法中的超类循环。

所以这不是我正在寻找的实际实现(因此这不是真正的答案),但我想它可以帮助理解精确算法的细微差别。

于 2010-07-26T20:25:30.570 回答
1

要了解 Franks 的反应,您需要一些背景信息:

编译器生成一个“发送字节码”,稍后由VM的字节码解释器执行(或jitted,但语义相同)。因此,您不会期望在任何类中找到实现,而是在 VM 中。

大多数其他 VM 是用 C、汇编程序或其他什么编写的......

但是:squeak VM 是用 Smalltalk 编写的,并由“Subset-of-Smalltalk-to-C-Compiler”(所谓的“俚语”,因为它不涵盖完整的 Smalltalk 语义)编译为 C。

使用 Smalltalk 编写的虚拟机当然可以在 Squeak 中进行开发、调试和测试(通过在图像中对图像运行 Slang 解释器)。这就是为什么您可以按照 Frank 的描述在 Interpreter 中找到实现的原因。

于 2010-08-25T11:55:31.287 回答