有人知道Pharo和Squeak的Cog VM是否能够通过以下访问器优化掉简单的间接变量访问:
SomeClass>>someProperty
^ someProperty
SomeClass>>someSecondProperty
^ someSecondProperty
只返回一个实例变量,所以像这样的方法:
SomeClass>>someMethod
^ self someProperty doWith: self someSecondProperty
不会比这样的方法慢:
SomeClass>>someMethod
^ someProperty doWith: someSecondProperty
我做了一些基准测试,它们的速度似乎大致相等,但我很好奇熟悉Cog的人是否肯定知道,因为如果存在差异(无论多么微小),那么可能会出现不合适的情况,无论多么罕见。
现在有一点成本,但它太少了,你不应该麻烦。如果您想要性能,您愿意更改代码的其他部分,而不是实例变量访问。
快速长凳:长凳^替补席=>#('52400000每秒。'49800000每秒。')差别看起来并没有那么大。
一旦被jited并执行一次,不同之处在于"self-iv"除了获取实例变量值之外,还执行内联缓存检查、cpu调用和cpu返回。调用和返回指令很可能是cpu预期的,而不是真正执行的。所以它是关于内联缓存检查的,这是一个非常便宜的操作。
开发中的内联编译器将添加的是,cpu调用和返回将真正随内联一起删除,这将涵盖cpu没有预料到的情况。此外,内联缓存检查可能会被删除,也可能不会被删除,这取决于具体情况。
有些细节,比如getter方法需要编译为本机代码,这会在机器代码区域中占据空间,这可能会增加机器代码区域垃圾收集的数量,但这甚至比内联缓存检查开销更有趣。
简而言之,现在的开销非常非常小,但将来开销会减少。
Clement
这是一个棘手的问题。。。我不知道确切的答案。但我可以通过一些线索帮助你学习如何自己检查。
您需要在映像中加载VMMaker包。在Pharo中,有一个程序可以通过从网络和github下载所有内容来构建这样的图像。看见https://github.com/pharo-project/pharo-vm
然后主要提示是,只返回实例变量的方法被编译为执行原语264+inst-var offset。。。(例如,您将通过检查Interval>>#first
或任何其他简单的inst-var getter来看到这一点)
在经典解释器VM中,这是在Interpreter>>internalExecuteNewMethod
中处理的
看起来你支付了方法查找的费用(一些缓存使其更便宜),但没有支付真正的方法激活的费用
我想这解释了调试器不能进入这样简单的方法。。。然而,这并不是一个真正的内联。
在COG中,如果使用任何解释器,StackInterpreter>>internalQuickPrimitiveResponse
中也会发生同样的情况。
至于JIT,它由Cogit>>compilePrimitive
处理,另请参阅genQuickReturnInstVar
的实现者。这也不是正确的内联,但您可以看到生成的指令很少。同样,我敢打赌,由于所谓的多态内联缓存(PIC),您通常不会为查找付出代价。
对于真正的内联,在快速浏览源代码之后,我没有发现任何线索
我的理解是,这将通过Sista VM的回调在图像侧发生,但这是正在进行的工作,只是我模糊的回忆。Clement Bera正在写一篇关于这一点的博客(西斯塔编年史http://clementbera.wordpress.com)
如果你害怕挖掘VMMaker源代码,我邀请你在vm-dev.lists.squeelfoundation.org上提问。我相信Eliot Miranda或Clement会很乐意给你一个更准确的答案。
编辑
我忘了告诉你上述经验的结论:我认为,如果你直接使用inst.var而不是getter,会有很小的差异,但这不应该是非常明显的,在所有情况下,你的编程风格都不应该受到这种可忽略的优化的指导。