Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【短】objc_msgSend's New Prototype #303

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

Nemocdz
Copy link
Collaborator

@Nemocdz Nemocdz commented Apr 7, 2020

下面是 PR 模板,使用说明:

  1. 填上对应的 Issue 链接或者 Issue ID
  2. 填上你认为本文阅读需要的时长
  3. 创建 PR
  4. 可以看到PR Checklist部分变成了可以勾选的方框,按照自己的实际情况进行勾选

这篇文章对应的 Issue 链接是:#278

本文的大致阅读时长:[8] 分钟。(这里按照你的主观感受填写即可,不需要非常准确,主要给读者一个参考)

PR Checklist:

请校对同学帮忙校对。


## 真正的原型

这背后其实隐藏着一个巨大且震惊的难题:`objc_msgSend` 的*真正*原型是什么?也就是说,它实际应该接受什么参数,返回什么结果?这个问题的答案并不简单。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

巨大且震惊的难题 => 巨大且难以回答的问题

surprisingly 是修饰 difficult,其实还是想说非常困难。更准确的翻译应该是:意外的难以回答,不过这样感觉太啰嗦了。


你可能听说过 `objc_msgSend` 是用汇编实现的,因为它调用非常频繁,需要压榨任何一点点性能。这个说法是对的,但并不完整。它不可能在*任何*速度下的 C 里面实现。

`objc_msgSend` 的最快路径做了一些关键的事情:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

的最快路径做了一些关键的事情 => 主要做了这几件事

fast path 应该是类似”快速浏览“的意思,或者“简单概括“。


这解释了上述的问题:`objc_msgSend` 的方法原型应该是它最终所调用方法实现的原型。

等等,动态方法查找和消息传递的整个核心难道不是让你不知道调用时的方法实现么?这没错!然而,你确实知道了实现的*类型签名*。编译器从 `@interface` 或 `@protocol` 的代码块里的方法声明中获得这些信息,并用于生成对应参数传递和返回值的获取代码。如果你重写了一个方法,但你没有匹配对应的类型签名,编译器会发出警告。这可以通过隐藏声明或者在运行时添加方法来解决,在这种情况下,你可以最终使用类型签名和调用侧不匹配的方法实现。这类调用的表现会取决于两种类型签名在 ABI 层面如何进行匹配,可能是完全合理和正确的行为(如果 ABI 匹配,那么所有参数对齐),也可能是不可预测的行为(如果没有匹配)。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

动态方法查找和消息传递的整个核心难道不是让你不知道调用时的方法实现么

这句有点太长,最好分割一下,比如:

之所以使用动态方法查找和消息传递,不就是因为你不知道调用方法的具体实现么

你确实知道了 => 你确实知道

??? objc_msgSend(id self, SEL _cmd, ???)
```

其中 `???` 表示未知的,它们取决于要调用的特定方法实现。当然,C 没有办法用类似这样的通配符来表示。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

表示未知的 => 表示未知

id objc_msgSend(id self, SEL _cmd, ...)
```

这实际上就是最近更改之前原型的样子。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最近更改之前原型的样子 => 最近这次改动之前的原型


## ABI 不匹配

和运行时相关的问题是调用侧的 ABI 是否和方法实现侧的 ABI 匹配。也就是说,接受者是否会从调用者传递时的相同位置和格式取回对应参数?如果调用方将参数放入 `$rdx`,则实现需要从 `$rdx` 中取回该参数,否则就会造成损坏。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果用了”是否“,就不需要用问号了,使用句号。


参数被传入寄存器。整型参数按 `rdi`、`rsi`、`rdx`、`rcx`、`r8` 和 `r9` 顺序传入对应的寄存器。浮点型参数传入 `xmm0` 到 `xmm7` 的 SSE 寄存器。当调用可变参数方法时,`al` 寄存器会设置传递参数所用到 SSE 寄存器的数量值。整型返回值放在 `rax` 和 `rdx` 中,而浮点型返回值放在 `xmm0` 和 `xmm1` 中。

可变参数函数的 ABI 几乎和普通函数的 ABI 相同。除了传进 `al` 的 SSE 寄存器的数量值之外。 然而,当使用可变参数函数的 ABI 去调用普通函数时,这并没有影响,因为普通函数会忽略 `al` 的内容。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这并没有影响 => 并不会有问题

为了说明这个问题,这里有一个简单的例子:

```objective-c
// 使用旧的可变参数原型的 objc_msgSend。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注释和下面代码没对齐


这背后其实隐藏着一个巨大且震惊的难题:`objc_msgSend` 的*真正*原型是什么?也就是说,它实际应该接受什么参数,返回什么结果?这个问题的答案并不简单。

你可能听说过 `objc_msgSend` 是用汇编实现的,因为它调用非常频繁,需要压榨任何一点点性能。这个说法是对的,但并不完整。它不可能在*任何*速度下的 C 里面实现。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的速度指的是什么?感觉没太看懂原文的意思。似乎作者是想说,因为 C 的一些机制,导致性能会受到影响,所以无法达到理论上的最大性能。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里我搜了下,感觉是用《Unsafe at Any Speed》这本书做比喻,这本书说的事汽车危险并不是只因为速度问题,这里应该是想说实现不了不只是因为 C 的性能问题

@Nemocdz
Copy link
Collaborator Author

Nemocdz commented Apr 10, 2020

一次校对修改完毕

Copy link
Collaborator

@WAMaker WAMaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

文章中 出现次数有些频繁,建议减少。


这背后其实隐藏着一个巨大且难以回答的问题:`objc_msgSend` 的*真正*原型是什么?也就是说,它实际应该接受什么参数,返回什么结果?这个问题的答案并不简单。

你可能听说过 `objc_msgSend` 是用汇编实现的,因为它调用非常频繁,需要压榨任何一点点性能。这个说法是对的,但并不完整。*任何*速度的 C 都无法实现(译者注:无法实现并不只是因为性能问题,源于《Unsafe at Any Speed》这本书)。
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最后一句是否可以译成:
C 语言无论什么样的实现都达不到现在的效果。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样翻译感觉和原文差距有点大,这里作者是个比喻,所以感觉保留直译比较好

Friday/20191011_objc_msgsends-new-prototype.md Outdated Show resolved Hide resolved
Friday/20191011_objc_msgsends-new-prototype.md Outdated Show resolved Hide resolved
Friday/20191011_objc_msgsends-new-prototype.md Outdated Show resolved Hide resolved
Friday/20191011_objc_msgsends-new-prototype.md Outdated Show resolved Hide resolved
对于返回值,我们可以尝试选择通用的东西。由于 Objective-C 是面向对象的,因此可以假定返回值是 `id`:

```objective-c
id objc_msgSend(id self, SEL _cmd, ???)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

怀疑这里的 _cmd 导致后面的文字都变成斜体了,需要修改。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应该不会的,我看了下预览

Friday/20191011_objc_msgsends-new-prototype.md Outdated Show resolved Hide resolved
@Nemocdz
Copy link
Collaborator Author

Nemocdz commented Apr 29, 2020

二次校对修改完毕,去掉了一些 “这”

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants