在 Squeak 中,我在哪里可以找到消息处理算法的代码?

发布于 2024-09-11 05:46:00 字数 547 浏览 6 评论 0原文

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

  1. curr <- 接收者的类
  2. Repeat while curr 不为 nil
    1. 在该类的方法中搜索选择器;如果存在,则调用它并返回
    2. curr <- curr 的超类
  3. self 上调用 doesNotUnderstand:

现在,respondsTo: 使用了一个非常相似的算法code> 方法,通过检查 respondsTo: 的代码确实可以看到。 我试图找到的是用于调用的上述算法的代码的位置

我知道 perform: 做了类似的事情,但我相信它不用于常规方法调用,而仅作为类似反射的方法调用机制(例如,当程序员直到运行时才知道方法名称时) 。

如果上面的代码也隐藏为原始指令,那么我在哪里可以找到原始调用?如果不是,我在哪里可以找到代码本身?

When sending a message to an object in Squeak, the runtime invocation algorithm is something like

  1. curr <- the receiver's class
  2. Repeat while curr isn't nil
    1. Search for the selector in that class's methods; if it's there, invoke it and return
    2. curr <- curr's superclass
  3. Call doesNotUnderstand: on self

Now, a very similar algorithm is used for the respondsTo: method, and indeed it can be seen by inspecting respondsTo:'s code. What I'm trying to find is the location of the code for the above algorithm used for invocation.

I know perform: does something similar but I believe it's not used for regular method invocation but only as a reflection-like method calling mechanism (e.g. when the method name is not known to the programmer until the runtime).

If the code above is also hidden as a primitive directive, where would I find the primitive call? If it isn't, where would I find the code itself?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

铁轨上的流浪者 2024-09-18 05:46:00

您可能想查看VMMaker。它的 Interpreter 类是执行 CompiledMethod 字节码的人,并且实际上会将消息发送到您的对象。

例如,如果您查看 Object>>respondsTo 的字节码:您将看到

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

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

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

虚拟机实际发送消息所使用的算法正如您在问题中概述的那样。该算法的实际实现在 Interpreter>>commonSend 中定义。查找算法位于 Interpreter>>lookupMethodInClass: 中,执行算法位于 Interpreter>>internalExecuteNewMethod 中。

前者的工作方式与您所描述的非常相似:

  1. List item
  2. 尝试在此类中查找方法。
  3. 如果没有找到,则在超类中查找。
  4. 如果递归失败,请尝试查找#doesNotUnderstand:
  5. 如果#doesNotUnderstand:在类层次结构中的任何位置都不存在,则抛出错误。

后者的工作方式如下:

  1. 如果它是原语,则运行原语。
  2. 如果不是,请激活新方法(创建新的激活记录)。
  3. (检查是否有中断。)

You'd probably want to look at VMMaker. Its Interpreter class is the guy that executes a CompiledMethod's bytecodes, and will actually send the messages to your objects.

For instance, if you look at the bytecodes for Object>>respondsTo: you'll see

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

The Interpreter reads in a bytecode, looks up that bytecode in its BytecodeTable (initialised in Interpreter class>>initialiseBytecodeTable) and executes the appropriate method. So <70> (#pushReceiverByteCode) pushes self onto the Interpreter's internal stack. Then (#bytecodePrimClass) boils down to "find self's class". <10> (#pushTemporaryVariableBytecode) pushes the argument to #respondsTo: onto the stack. The interesting part happens with (#sendLiteralSelectorBytecode), which calls self normalSend. #normalSend in turn figures out the class of the receiver (self class in this case), and then calls self commonSend, which finds the actual method we seek to run, and then runs it.

I'm a VM newbie; the above might not be the absolute best place to see the algorithm in action, etc., (or even the best explanation) but I hope it's a good place to start.

The algorithm used by the VM to actually send a message is as you outline in your question. The actual implementation of that algorithm's defined in Interpreter>>commonSend. The lookup algorithm's in Interpreter>>lookupMethodInClass: and the execution algorithm's in Interpreter>>internalExecuteNewMethod.

The former works much as you describe:

  1. List item
  2. Try find the method in this class.
  3. If not found, look in the superclass.
  4. If this recursively fails, try find #doesNotUnderstand:
  5. If #doesNotUnderstand: doesn't exist anywhere in the class hierarchy, throw an error.

The latter works like this:

  1. If it's a primitive, run the primitive.
  2. If it's not, activate the new method (create a new activation record).
  3. (Check for interrupts.)
把回忆走一遍 2024-09-18 05:46:00

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

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

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

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

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

Digging some more, the ContextPart class is an interpreter capable of running bytecode. According to its documentation:

[its methods relevant to this question] exactly parallel the operation of the Smalltalk machine itself.

If we check how it interprets bytecode,

  1. Its interpret method calls its interpretNextInstructionFor: for each instruction.
  2. interpretNextInstructionFor: calls send:super:numArgs: when a send instruction is encountered.
  3. send:super:numArgs: calls send:to:with:super: (assuming it is not a primitive message).
  4. send:to:with:super: uses Behavior's lookupSelector: to locate the correct selector to use.
  5. Behavior's lookupSelector: is the one responsible for the superclass loop in the algorithm appearing in the question.

So this is not the actual implementation I was looking for (and thus this is not really an answer), but I guess that it can help with understanding the nuances of the precise algorithm.

烈酒灼喉 2024-09-18 05:46:00

要理解 Franks 的响应,您需要一些背景信息:

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

大多数其他 VM 都是用 C、汇编程序或其他语言编写的...

但是:squeak VM 是用 Smalltalk 编写的,并由“Smalltalk 到 C 编译器的子集”(所谓的“俚语”)编译为 C ,因为它没有涵盖完整的 Smalltalk 语义)。

该虚拟机是用 Smalltalk 编写的,当然可以在 Squeak 中进行开发、调试和测试(通过在镜像中运行镜像上的俚语解释器)。这就是为什么您可以在 Interpreter 中找到 Frank 所描述的实现。

To understand Franks response, you need some background info:

the compiler generates a "send bytecode", which is later executed by the VM's bytecode interpreter (or jitted, but the semantics is the same). Thus, you would not expect to find the implementation in any class, but in the VM.

Most other VM's are written in C, Assembler or what else...

However: the squeak VM is written in Smalltalk, and compiled to C by a "Subset-of-Smalltalk-to-C-Compiler" (so called "Slang", because it does not cover the full Smalltalk semantics).

Being written in Smalltalk, that VM can of course be developed, debugged and tested from within Squeak (by running the Slang-interpreter on the image from within the image). That is why you can find the implementation in Interpreter as described by Frank.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文