优化Smalltalk中的ifTrue:ifFalse:
Smalltalk蓝皮书说,编译器使用特殊操作码优化优化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
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