True basicNew ifTrue: [ "some code" ] hehe raises NonBooleanReceiver :) 2013/6/26 Camillo Bruni <camillobruni@gmail.com>
why not, let's "forbid" them with an error message!
=> maybe you can and error to #become: on nil / true / false as well?
On 2013-06-26, at 14:20, Torsten Bergmann <astares@gmx.de> wrote:
Boolean new -> error Boolean basicNew -> is possible
should we care?
-- Clément Béra Mate Virtual Machine Engineer Bâtiment B 40, avenue Halley 59650 *Villeneuve d'Ascq*
Because you don't know the tricks... This one should be just fine True basicNew ifTrue: [ "some code" ] yourself 2013/6/26 Clément Bera <bera.clement@gmail.com>
True basicNew ifTrue: [ "some code" ]
hehe raises NonBooleanReceiver :)
2013/6/26 Camillo Bruni <camillobruni@gmail.com>
why not, let's "forbid" them with an error message!
=> maybe you can and error to #become: on nil / true / false as well?
On 2013-06-26, at 14:20, Torsten Bergmann <astares@gmx.de> wrote:
Boolean new -> error Boolean basicNew -> is possible
should we care?
-- Clément Béra Mate Virtual Machine Engineer Bâtiment B 40, avenue Halley 59650 *Villeneuve d'Ascq*
Actually this code: True basicNew ifTrue: [ "some code" ] works fine on the latest Pharo 3 because of Opal :) But nice trick for the old compiler :) 2013/6/26 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>
Because you don't know the tricks... This one should be just fine
True basicNew ifTrue: [ "some code" ] yourself
2013/6/26 Clément Bera <bera.clement@gmail.com>
True basicNew ifTrue: [ "some code" ]
hehe raises NonBooleanReceiver :)
2013/6/26 Camillo Bruni <camillobruni@gmail.com>
why not, let's "forbid" them with an error message!
=> maybe you can and error to #become: on nil / true / false as well?
On 2013-06-26, at 14:20, Torsten Bergmann <astares@gmx.de> wrote:
Boolean new -> error Boolean basicNew -> is possible
should we care?
-- Clément Béra Mate Virtual Machine Engineer Bâtiment B 40, avenue Halley 59650 *Villeneuve d'Ascq*
I guess that once detected adding a Lint rule is better than restrictions everywhere.
On Wed, 26 Jun 2013, Clément Bera wrote:
Actually this code:Â True basicNew ifTrue: [ "some code" ] works fine on the latest Pharo 3 because of Opal :)
So the Opal compiler lacks important optimizations. :) Levente
But nice trick for the old compiler :)
2013/6/26 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> Because you don't know the tricks... This one should be just fine
True basicNew ifTrue: [ "some code" ] yourself
2013/6/26 Clément Bera <bera.clement@gmail.com> True basicNew ifTrue: [ "some code" ]
hehe raises NonBooleanReceiver :)
2013/6/26 Camillo Bruni <camillobruni@gmail.com> why not, let's "forbid" them with an error message!
=> maybe you can and error to #become: on nil / true / false as well?
On 2013-06-26, at 14:20, Torsten Bergmann <astares@gmx.de> wrote:
> Boolean new     -> error > Boolean basicNew  -> is possible > > should we care? >
-- Clément BéraMate Virtual Machine Engineer Bâtiment B 40, avenue Halley 59650 Villeneuve d'Ascq
On Wed, Jun 26, 2013 at 11:20 PM, Levente Uzonyi <leves@elte.hu> wrote:
On Wed, 26 Jun 2013, Clément Bera wrote:
Actually this code:
True basicNew ifTrue: [ "some code" ] works fine on the latest Pharo 3 because of Opal :)
So the Opal compiler lacks important optimizations. :)
Not at all. In fact, the the code is optimized and falls back to the normal lookup in case of exceptional #mustBeBoolean, so the existing code keeps running the same speed ;)
Levente
But nice trick for the old compiler :)
2013/6/26 Nicolas Cellier <nicolas.cellier.aka.nice@**gmail.com<nicolas.cellier.aka.nice@gmail.com>
Because you don't know the tricks... This one should be just fine
True basicNew ifTrue: [ "some code" ] yourself
2013/6/26 Clément Bera <bera.clement@gmail.com> True basicNew ifTrue: [ "some code" ]
hehe raises NonBooleanReceiver :)
2013/6/26 Camillo Bruni <camillobruni@gmail.com> why not, let's "forbid" them with an error message!
=> maybe you can and error to #become: on nil / true / false as well?
On 2013-06-26, at 14:20, Torsten Bergmann <astares@gmx.de> wrote:
> Boolean new -> error > Boolean basicNew -> is possible > > should we care? >
-- Clément BéraMate Virtual Machine Engineer
Bâtiment B 40, avenue Halley 59650 Villeneuve d'Ascq
On Wed, 26 Jun 2013, Guillermo Polito wrote:
On Wed, Jun 26, 2013 at 11:20 PM, Levente Uzonyi <leves@elte.hu> wrote: On Wed, 26 Jun 2013, Clément Bera wrote:
Actually this code:Â True basicNew ifTrue: [ "some code" ] works fine on the latest Pharo 3 because of Opal :)
So the Opal compiler lacks important optimizations. :)
Not at all. In fact, the the code is optimized and falls back to the normal lookup in case of exceptional #mustBeBoolean, so the existing code keeps running the same speed ;)
So it generates a bunch of extra bytecodes for every #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: messages, in order to make this thing work? Or is there a trick to avoid the duplicaiton of the code in the blocks? Levente
Â
Levente
But nice trick for the old compiler :)
2013/6/26 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> Â Â Â Because you don't know the tricks... This one should be just fine
   True basicNew ifTrue: [ "some code" ] yourself
2013/6/26 Clément Bera <bera.clement@gmail.com>    True basicNew ifTrue: [ "some code" ]
hehe raises NonBooleanReceiver :)
2013/6/26 Camillo Bruni <camillobruni@gmail.com> Â Â Â why not, let's "forbid" them with an error message!
   => maybe you can and error to #become: on nil / true / false as well?
   On 2013-06-26, at 14:20, Torsten Bergmann <astares@gmx.de> wrote:
   > Boolean new     -> error    > Boolean basicNew  -> is possible    >    > should we care?    >
-- Clément BéraMate Virtual Machine Engineer Bâtiment B 40, avenue Halley 59650 Villeneuve d'Ascq
2013/6/27 Levente Uzonyi <leves@elte.hu>
On Wed, 26 Jun 2013, Guillermo Polito wrote:
On Wed, Jun 26, 2013 at 11:20 PM, Levente Uzonyi <leves@elte.hu> wrote: On Wed, 26 Jun 2013, Clément Bera wrote:
Actually this code: True basicNew ifTrue: [ "some code" ] works fine on the latest Pharo 3 because of Opal :)
So the Opal compiler lacks important optimizations. :)
Actually Opal generates almost the same bytecode as the old compiler. As a proof, Benchmarks run at the same speed when compiled with one or the other compiler. So no lack of optimizations.
Moreover Pharo and Squeak cannot be compiled without optimizing control flow structure or the compilation fails by image crash. This is due for example to the implementation of BlockClosure>>whileTrue: .
Not at all. In fact, the the code is optimized and falls back to the normal lookup in case of exceptional #mustBeBoolean, so the existing code keeps running the same speed ;)
So it generates a bunch of extra bytecodes for every #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: messages, in order to make this thing work? Or is there a trick to avoid the duplicaiton of the code in the blocks?
I understood the problem. In Pharo 3 we will support conditional optimized messages ( #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: ) sent on non boolean receiver. However, this feature will be slow, so one should not use it too much (as #become:, #isKindOf:, ...). Basically Opal compiles on the fly without optimizing it the conditional messageNode as a DoIt, run it, and jump in the context to the pc corresponding to the next ast node. We don't generate extra bytecode as you suggested, because it will grow the size of the image a lot and slow down the system with extra conditions. Right now the feature is still under development and very buggy (it is just a prototype). It is activated only when Opal is set as default compiler, which is wrong, and there is a bug report. This bug report will be fixed during the sprint on Friday. So actually I didn't look carefully enough but: True basicNew ifTrue: [ "some code" ] works fine because it sends it to a NonBooleanReceiver but Pharo 3 supports #ifTrue: sent on a NonBooleanReceiver. However, what you can do in Pharo 3 / Opal if you know explicitly that you will send the optimized message to a NonBooleanReceiver, to avoid slowness due to on the fly do it compilation, you can specify it to the compiler in the class: MyClass class>>#compiler ^ super compiler options: #(- optInlineIf) or in the method : MyClass>>#foo <compilerOptions: #(- optInlineIf)> ^ #myNonBooleanObject ifTrue: [ 1 ] ifFalse: [ 0 ] There are different options like this one. I wrote them down here to remember (section compilerOptions): http://clementbera.wordpress.com/2013/05/28/modular-compilation-with-opal/ But it is not very nicely written, I've just write it to remember .. Compiler options as this one are not for daily use, there are here to enable some stuff like boolean proxies.
Levente
Levente
But nice trick for the old compiler :)
2013/6/26 Nicolas Cellier <nicolas.cellier.aka.nice@** gmail.com <nicolas.cellier.aka.nice@gmail.com>> Because you don't know the tricks... This one should be just fine
True basicNew ifTrue: [ "some code" ] yourself
2013/6/26 Clément Bera <bera.clement@gmail.com> True basicNew ifTrue: [ "some code" ]
hehe raises NonBooleanReceiver :)
2013/6/26 Camillo Bruni <camillobruni@gmail.com> why not, let's "forbid" them with an error message!
=> maybe you can and error to #become: on nil / true / false as well?
On 2013-06-26, at 14:20, Torsten Bergmann < astares@gmx.de> wrote:
> Boolean new -> error > Boolean basicNew -> is possible > > should we care? >
-- Clément Béra Mate Virtual Machine Engineer Bâtiment B 40, avenue Halley 59650 *Villeneuve d'Ascq*
On Jun 27, 2013, at 8:16 AM, Clément Bera <bera.clement@gmail.com> wrote:
In Pharo 3 we will support conditional optimized messages ( #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: ) sent on non boolean receiver. However, this feature will be slow, so one should not use it too much (as #become:, #isKindOf:, ...). Basically Opal compiles on the fly without optimizing it the conditional messageNode as a DoIt, run it, and jump in the context to the pc corresponding to the next ast node. We don't generate extra bytecode as you suggested, because it will grow the size of the image a lot and slow down the system with extra conditions.
It's actually not a lot of code. We need to debug/fix it for all the cases, though, this might add some more complexity: mustBeBooleanInMagic: context "Permits to redefine methods inlined by compiler. Take the ast node corresponding to the mustBeBoolean error, compile it on the fly with Opal and executes it as a DoIt. Then resume the execution of the context." | proceedValue sendNode selector expression arguments methodNode method offset position | context skipBackBeforeJump. sendNode := context sourceNode sourceNodeForPC: context pc. position := sendNode irInstruction bytecodeOffset. offset := sendNode irInstruction nextBytecodeOffsetAfterJump - position. expression := sendNode copy asSequenceNode transformLastToReturn. selector := #ExecuteUnOptimzedIn:. arguments := {(RBVariableNode named:'ThisContext')}. methodNode := RBMethodNode selector: selector arguments: arguments body: expression. context tempNames do: [:tempName | methodNode :=methodNode rewriteTempNamedWrite: tempName forContext: context. methodNode :=methodNode rewriteTempNamedRead: tempName forContext: context. ]. methodNode compilationContext: sendNode methodNode compilationContext. methodNode compilationContext class: UndefinedObject; compilerOptions: #(+ optIlineNone). method := methodNode generateWithSource. context jump: offset. proceedValue := self withArgs: {context} executeMethod: method. ^proceedValue
On Thu, 27 Jun 2013, Marcus Denker wrote:
On Jun 27, 2013, at 8:16 AM, Clément Bera <bera.clement@gmail.com> wrote:
In Pharo 3 we will support conditional optimized messages ( #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: ) sent on non boolean receiver. However, this feature will be slow, so one should not use it too much (as #become:, #isKindOf:, ...). Basically Opal compiles on the fly without optimizing it the conditional messageNode as a DoIt, run it, and jump in the context to the pc corresponding to the next ast node. We don't generate extra bytecode as you suggested, because it will grow the size of the image a lot and slow down the system with extra conditions.
It's actually not a lot of code. We need to debug/fix it for all the cases, though, this might add some more complexity:
So Opal generates the same code as the old compiler. It's just a different implementation of #mustBeBoolean, what makes the difference. IIUC whenever the receiver of the optimized conditional message is not true or false, the code is decompiled, then a new CompiledMethod is created without the optimization, it's injected onto the stack, and the execution is continued from before where the jumpTrue: or jumpFalse: was in the original method. As Clément wrote, this is rather slow. Maybe even too slow to be useful. A possible improvement would be to permanently replace the original compiled method with the deoptimized one, since the receiver is likely to be not one of the unique Boolean instances during futher executions of the method. This way the decompilation has to be done only once. Though these kind of code mutations behind the scene can cause some headache for someone who's trying to optimize the code. Levente
mustBeBooleanInMagic: context "Permits to redefine methods inlined by compiler. Take the ast node corresponding to the mustBeBoolean error, compile it on the fly with Opal and executes it as a DoIt. Then resume the execution of the context."
| proceedValue sendNode selector expression arguments methodNode method offset position | context skipBackBeforeJump.
sendNode := context sourceNode sourceNodeForPC: context pc. position := sendNode irInstruction bytecodeOffset. offset := sendNode irInstruction nextBytecodeOffsetAfterJump - position.
expression := sendNode copy asSequenceNode transformLastToReturn. selector := #ExecuteUnOptimzedIn:. arguments := {(RBVariableNode named:'ThisContext')}. methodNode := RBMethodNode selector: selector arguments: arguments body: expression.
context tempNames do: [:tempName | methodNode :=methodNode rewriteTempNamedWrite: tempName forContext: context. methodNode :=methodNode rewriteTempNamedRead: tempName forContext: context. ]. methodNode compilationContext: sendNode methodNode compilationContext. methodNode compilationContext class: UndefinedObject; compilerOptions: #(+ optIlineNone).
method := methodNode generateWithSource.
context jump: offset.
proceedValue := self withArgs: {context} executeMethod: method. ^proceedValue
On Jun 27, 2013, at 5:17 PM, Levente Uzonyi <leves@elte.hu> wrote:
On Thu, 27 Jun 2013, Marcus Denker wrote:
On Jun 27, 2013, at 8:16 AM, Clément Bera <bera.clement@gmail.com> wrote:
In Pharo 3 we will support conditional optimized messages ( #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: ) sent on non boolean receiver. However, this feature will be slow, so one should not use it too much (as #become:, #isKindOf:, ...). Basically Opal compiles on the fly without optimizing it the conditional messageNode as a DoIt, run it, and jump in the context to the pc corresponding to the next ast node. We don't generate extra bytecode as you suggested, because it will grow the size of the image a lot and slow down the system with extra conditions.
It's actually not a lot of code. We need to debug/fix it for all the cases, though, this might add some more complexity:
So Opal generates the same code as the old compiler. It's just a different implementation of #mustBeBoolean, what makes the difference. IIUC whenever the receiver of the optimized conditional message is not true or false, the code is decompiled, then a new CompiledMethod is created without the optimization, it's injected onto the stack, and the execution is continued from before where the jumpTrue: or jumpFalse: was in the original method.
As Clément wrote, this is rather slow. Maybe even too slow to be useful. A possible improvement would be to permanently replace the original compiled method with the deoptimized one, since the receiver is likely to be not one of the unique Boolean instances during futher executions of the method. This way the decompilation has to be done only once. Though these kind of code mutations behind the scene can cause some headache for someone who's trying to optimize the code.
The question is if it makes sense to invest in these things on top of the current infrastructure. Marcus
On Thu, 27 Jun 2013, Marcus Denker wrote:
On Jun 27, 2013, at 5:17 PM, Levente Uzonyi <leves@elte.hu> wrote:
On Thu, 27 Jun 2013, Marcus Denker wrote:
On Jun 27, 2013, at 8:16 AM, Clément Bera <bera.clement@gmail.com> wrote:
In Pharo 3 we will support conditional optimized messages ( #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: ) sent on non boolean receiver. However, this feature will be slow, so one should not use it too much (as #become:, #isKindOf:, ...). Basically Opal compiles on the fly without optimizing it the conditional messageNode as a DoIt, run it, and jump in the context to the pc corresponding to the next ast node. We don't generate extra bytecode as you suggested, because it will grow the size of the image a lot and slow down the system with extra conditions.
It's actually not a lot of code. We need to debug/fix it for all the cases, though, this might add some more complexity:
So Opal generates the same code as the old compiler. It's just a different implementation of #mustBeBoolean, what makes the difference. IIUC whenever the receiver of the optimized conditional message is not true or false, the code is decompiled, then a new CompiledMethod is created without the optimization, it's injected onto the stack, and the execution is continued from before where the jumpTrue: or jumpFalse: was in the original method.
As Clément wrote, this is rather slow. Maybe even too slow to be useful. A possible improvement would be to permanently replace the original compiled method with the deoptimized one, since the receiver is likely to be not one of the unique Boolean instances during futher executions of the method. This way the decompilation has to be done only once. Though these kind of code mutations behind the scene can cause some headache for someone who's trying to optimize the code.
The question is if it makes sense to invest in these things on top of the current infrastructure.
Not really, but it seems like you've already started implementing it. Levente
Marcus
On 26 Jun 2013, at 14:20, Torsten Bergmann <astares@gmx.de> wrote:
Boolean new -> error Boolean basicNew -> is possible
should we care?
true, false and nil are special since they are unique constant instances, right ? To support that notion, it would seem to be sensible to restrict creating bogus instances. This is already done for #new. But maybe #basicNew for these classes cannot be overridden and is needed somewhere else ? Sven
participants (9)
-
Camillo Bruni -
Clément Bera -
Esteban A. Maringolo -
Guillermo Polito -
Levente Uzonyi -
Marcus Denker -
Nicolas Cellier -
Sven Van Caekenberghe -
Torsten Bergmann