优化Smalltalk中的ifTrue:ifFalse:

优化Smalltalk中的ifTrue:ifFalse:,smalltalk,Smalltalk,Smalltalk蓝皮书说,编译器使用特殊操作码优化ifTrue:ifFalse:和friends,以避免创建闭包和对实际布尔对象执行动态调度 如果我理解正确,那么: o ifTrue: [ ^ 'yes' ] ifElse: [ ^ 'no' ] …变得像: push o jump_if_false 1 return 'yes' jump 2 1: return 'no' 2: (我查过了,GNU Smalltalk就是这么做的。) 如果o是一个Bo

Smalltalk蓝皮书说,编译器使用特殊操作码优化
ifTrue:ifFalse:
和friends,以避免创建闭包和对实际布尔对象执行动态调度

如果我理解正确,那么:

o ifTrue: [ ^ 'yes' ] ifElse: [ ^ 'no' ]
…变得像:

    push o
    jump_if_false 1
    return 'yes'
    jump 2
1:
    return 'no'
2:
(我查过了,GNU Smalltalk就是这么做的。)

如果
o
是一个
Boolean
,这就可以了,但我不明白如果不是的话会发生什么。毕竟,编译器不知道
o
是什么类型。它不能保证它是一个布尔值。它甚至不知道
ifTrue:ifFalse:
方法是否具有传统的语义

例如:

Fnord ifTrue: tb ifFalse: fb
    "muhahaha"
    tb value: self.
    fb value: self and: 9.
    ^ 7
要使此实现工作,true和false块必须是闭包,分别使用一个和两个参数。那么编译器如何知道如何生成闭包呢?还是允许编译器在这种情况下中断?

以下是字节码(我使用的方言)

以下是本地化代码(简化):

如果
receiver
Fnord
的一个实例(即使
receiver
理解
#ifTrue:ifFalse:
),此代码将以
#mustBeBoolean
失败。原因是,在这种情况下,编译器将优化
#ifTrue:ifFalse:
,正如我们上面看到的那样,而不是将其作为常规消息发送

然而,表达方式

receiver ifTrue: [:a | <whatever>] ifFalse: [:a :b | <your code>]
receiver ifTrue:[:a |]ifFalse:[:a:b |]

fa:=[:a |]。
fb:=[:a:b |]。
接收器ifTrue:fa ifFalse:fb

不会被优化,这意味着将发送
#ifTrue:ifFalse:

在Squeak中有效的方法是只发送#您自己到其中一个块以击败优化。。。自我测试某事是否真实:[自我做某事]自己是否真实:[自我做另一件事]。还有待观察gst编译器在这种情况下会做什么……我突然想到,如果
o
不是
布尔值,那么
mustBeBoolean
可以做与
o ifTrue:[true]ifFalse:[false]
等效的事情,将其转换为基本布尔值;在这一点上,优化后的代码就可以工作了。此外,实验表明,gst不会优化第二种情况。而且,是的,在块上调用
自己
也会破坏优化。这一切都是有道理的,谢谢。(真正有趣的是,gst不会优化
o如果真的:[|j | j:=1.j]ifFalse:[2]
…)@aka.nice这是有道理的。解析器将告诉您自己
[
]不是
BlockNode
,而是
MessageNode
,只有当参数是不带参数的BlockNode时,才会进行优化。
    cmp eax, false       ; test jump false
    jz @2
    cmp eax, true
    jz @1
    call mustBeBoolean   ; <--- here!
@1: mov eax, 'true'
    ret
    jmp @3               ; jump
@2: mov eax, 'no'
    ret
@3: move eax, esi
    ret
receiver ifTrue: ['yes'] ifFalse: ['no']
receiver ifTrue: [:a | <whatever>] ifFalse: [:a :b | <your code>]
fa := [:a | <whatever>].
fb := [:a :b | <yourcode>].
receiver ifTrue: fa ifFalse: fb