Smalltalk动态查找优化

时间:2016-05-20 07:37:35

标签: smalltalk dynamic-dispatch

在Smalltalk中,在运行时查找方法可能涉及大量步骤,因为子类的方法字典在其超类中不包含方法,并且需要指针追踪来查找方法。优化将是每个子类将所有超类方法存储在其方法字典中 问题:如何做到这一点?

一个明显的缺点是空间成本,但我只是想知道如何在Smalltalk中完成这项工作?这与为最近调用的方法创建单独的缓存不同。

3 个答案:

答案 0 :(得分:5)

有很多方法可以缓存查找结果。只需阅读一些基本的VMimplementation论文 - 从绿皮书开始。你甚至可以在网上免费找到t - http://stephane.ducasse.free.fr/FreeBooks.html并查看“历史的位数,建议的话”的底部。 普通解释器可以使用简单的散列键控缓存。翻译虚拟机可以进入内联缓存,多态内联缓存,自适应缓存......不需要像C ++ vtables一样痛苦,这几乎就是你所建议的。 我们已经覆盖了几十年。它已经解决了。

答案 1 :(得分:4)

  

在Smalltalk中,在运行时查找方法可能涉及大量步骤,因为子类的方法字典在其超类中不包含方法

对于不尝试进行任何优化的解释Smalltalk也是如此,许多Smalltalks(例如Pharo)实际上已经编译并且虚拟机中有很多优化...所以消息查找肯定不是我想要的担心表现明智。

至于所谓的阶级扁平化...天真的方式实际上是微不足道的,你只需要复制所有的父方法

Child withAllSuperclassesDo: [ :cls |
    cls methods do: [ :m |
        (Child selectors includes: m selector) ifFalse: [ 
            Child compile: m sourceCode classified: m protocol
        ]
    ]
]

确定所有的方法都在那里

enter image description here

您可能不希望复制完整的层次结构,但可以轻松地将其限制为例如包裹,或几个祖先。

super怎么样?

super可能存在一个不那么好的捕获,它依赖于位于层次结构中的特定位置。例如,如果您在使用super的父级中覆盖某些方法和调用方法...然后将其展平......您可能会陷入无限循环,或者更糟。

所以你可能需要分析源代码,如果所有这些引用都是正确的......我不确定这是否可以自动完成,因为它可能取决于代码的逻辑,你需要用自己的代码来分析眼睛和头脑。这也意味着你不能盲目地复制所有方法或从多个类指向同一个方法,因为super具有不同的含义。

正如阿莫斯恰当地指出的那样......这是不可能的。

更新以回答@ aka.nice的评论(并进一步说明为什么super有问题)

enter image description here enter image description here

在展平之前的左边,在右边之后。

几乎任何时候包含super的方法都会做某事(应该如此),你基本上至少要调用两次这个行为。

答案 2 :(得分:2)

有些方言使用另一种方法来最小化枚举MethodDictionaries链所需的操作次数:所谓的MDA或方法字典数组。

这个想法是让类在第一个插槽中保留一个包含其{1}}实例的数组,然后保留其超类的MD,依此类推。

这种技术的一个好处是它可以在实例级别实现。可以存储类的MD,而不是将类存储在对象头中。这与方法发送中发生的类检查完全兼容,但它变为MDA - 而是检查。

此外,如果您重新启用MDA,则可以向其添加行为,以使其支持嵌套。这样,外部数组可能包含MDA或嵌套MDs。嵌套可用于添加特定于实例的行为,而无需从类的MDA中删除:将特定于实例的行为放在MDA中并将其存储在插槽1中,然后放入{{1}插槽2中的类。如果类的MD发生更改,则实例不必执行任何特殊操作即可附加到已修改的MDA。 (如果实例在插槽1中创建了自己的MDA及其MDA,在后续插槽中创建了类MDA,则该类的MD将与实例分离一个)

BTW,空间成本很小,因为没有任何重复。