Hi all,
I have a simple method containing an ifTrue: message. I have compiled it normally, which uses macro transformations: 17 <10> pushTemp: 0 18 <9B> jumpFalse: 23 19 <10> pushTemp: 0 20 <20> pushConstant: 4 21 <B0> send: + 22 <7C> returnTop 23 <78> returnSelf and I have compiled it using Klaus Witzel's nifty compiler changes to remove macro transformations and the result is an explicit message send of #ifTrue: 21 <10> pushTemp: 0 22 <89> pushThisContext: 23 <75> pushConstant: 0 24 <C8> send: blockCopy: 25 <A4 04> jumpTo: 31 27 <10> pushTemp: 0 28 <21> pushConstant: 4 29 <B0> send: + 30 <7C> returnTop 31 <E0> send: ifTrue: 32 <87> pop 33 <78> returnSelf I would like to check the receiver of the ifTrue:, the 1st method arg in this case (Temp: 0), to see if a certain situation exists (is it a local reference to an object?). If it is true, I would like to run the optimal code from the first example, instead of the longer second example. How could we do that? Something like this? Could it be done entirely by the compiler, given the existence of the bytecode routine for #testLocalReference? 21 <10> pushTemp: 0 22 <??> testLocalReference 23 <??> jumpFalse: 30 24 <10> pushTemp: 0 25 <??> jumpFalse: 40 26 <10> pushTemp: 0 27 <20> pushConstant: 4 28 <B0> send: + 29 <7C> returnTop 30 <89> pushThisContext: 31 <75> pushConstant: 0 32 <C8> send: blockCopy: 33 <?? ??> jumpTo: 38 34 <10> pushTemp: 0 35 <21> pushConstant: 4 36 <B0> send: + 37 <7C> returnTop 38 <E0> send: ifTrue: 39 <87> pop 40 <78> returnSelf Thanks! Rob |
No, i think you'd better change the implementation of #jumpFalse bytecode.
If you see that receiver is non-local , then simply do message send. And, i think you can safely use info from jump bytecode to extract block contents (bytes 19 - 22 is the block body). On 19/10/2007, Robert Withers <[hidden email]> wrote: > Hi all, > > I have a simple method containing an ifTrue: message. I have > compiled it normally, which uses macro transformations: > > 17 <10> pushTemp: 0 > 18 <9B> jumpFalse: 23 > 19 <10> pushTemp: 0 > 20 <20> pushConstant: 4 > 21 <B0> send: + > 22 <7C> returnTop > 23 <78> returnSelf > > and I have compiled it using Klaus Witzel's nifty compiler changes to > remove macro transformations and the result is an explicit message > send of #ifTrue: > > 21 <10> pushTemp: 0 > 22 <89> pushThisContext: > 23 <75> pushConstant: 0 > 24 <C8> send: blockCopy: > 25 <A4 04> jumpTo: 31 > 27 <10> pushTemp: 0 > 28 <21> pushConstant: 4 > 29 <B0> send: + > 30 <7C> returnTop > 31 <E0> send: ifTrue: > 32 <87> pop > 33 <78> returnSelf > > I would like to check the receiver of the ifTrue:, the 1st method arg > in this case (Temp: 0), to see if a certain situation exists (is it a > local reference to an object?). If it is true, I would like to run > the optimal code from the first example, instead of the longer second > example. How could we do that? Something like this? Could it be > done entirely by the compiler, given the existence of the bytecode > routine for #testLocalReference? > > 21 <10> pushTemp: 0 > 22 <??> testLocalReference > 23 <??> jumpFalse: 30 > 24 <10> pushTemp: 0 > 25 <??> jumpFalse: 40 > 26 <10> pushTemp: 0 > 27 <20> pushConstant: 4 > 28 <B0> send: + > 29 <7C> returnTop > 30 <89> pushThisContext: > 31 <75> pushConstant: 0 > 32 <C8> send: blockCopy: > 33 <?? ??> jumpTo: 38 > 34 <10> pushTemp: 0 > 35 <21> pushConstant: 4 > 36 <B0> send: + > 37 <7C> returnTop > 38 <E0> send: ifTrue: > 39 <87> pop > 40 <78> returnSelf > > > Thanks! > Rob > > > -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Rob Withers
Igor, I'm afraid you've lost me. What would the bytecodes look like in your
proposal? From what you've said, wouldn't the #jumpFalse need to know what the literal to send is? I also don't understand how it would extract the block contents. thanks, Rob ----- Original Message ----- From: "Igor Stasenko" <[hidden email]> To: "The general-purpose Squeak developers list" <[hidden email]> Sent: Thursday, October 18, 2007 3:06 PM Subject: Re: runtime compiled method optimizations > No, i think you'd better change the implementation of #jumpFalse > bytecode. > If you see that receiver is non-local , then simply do message send. > And, i think you can safely use info from jump bytecode to extract > block contents > (bytes 19 - 22 is the block body). > > On 19/10/2007, Robert Withers <[hidden email]> wrote: >> Hi all, >> >> I have a simple method containing an ifTrue: message. I have >> compiled it normally, which uses macro transformations: >> >> 17 <10> pushTemp: 0 >> 18 <9B> jumpFalse: 23 >> 19 <10> pushTemp: 0 >> 20 <20> pushConstant: 4 >> 21 <B0> send: + >> 22 <7C> returnTop >> 23 <78> returnSelf >> >> and I have compiled it using Klaus Witzel's nifty compiler changes to >> remove macro transformations and the result is an explicit message >> send of #ifTrue: >> >> 21 <10> pushTemp: 0 >> 22 <89> pushThisContext: >> 23 <75> pushConstant: 0 >> 24 <C8> send: blockCopy: >> 25 <A4 04> jumpTo: 31 >> 27 <10> pushTemp: 0 >> 28 <21> pushConstant: 4 >> 29 <B0> send: + >> 30 <7C> returnTop >> 31 <E0> send: ifTrue: >> 32 <87> pop >> 33 <78> returnSelf >> >> I would like to check the receiver of the ifTrue:, the 1st method arg >> in this case (Temp: 0), to see if a certain situation exists (is it a >> local reference to an object?). If it is true, I would like to run >> the optimal code from the first example, instead of the longer second >> example. How could we do that? Something like this? Could it be >> done entirely by the compiler, given the existence of the bytecode >> routine for #testLocalReference? >> >> 21 <10> pushTemp: 0 >> 22 <??> testLocalReference >> 23 <??> jumpFalse: 30 >> 24 <10> pushTemp: 0 >> 25 <??> jumpFalse: 40 >> 26 <10> pushTemp: 0 >> 27 <20> pushConstant: 4 >> 28 <B0> send: + >> 29 <7C> returnTop >> 30 <89> pushThisContext: >> 31 <75> pushConstant: 0 >> 32 <C8> send: blockCopy: >> 33 <?? ??> jumpTo: 38 >> 34 <10> pushTemp: 0 >> 35 <21> pushConstant: 4 >> 36 <B0> send: + >> 37 <7C> returnTop >> 38 <E0> send: ifTrue: >> 39 <87> pop >> 40 <78> returnSelf >> >> >> Thanks! >> Rob >> >> >> > > > -- > Best regards, > Igor Stasenko AKA sig. > > |
On 19/10/2007, Rob Withers <[hidden email]> wrote:
> Igor, I'm afraid you've lost me. What would the bytecodes look like in your > proposal? From what you've said, wouldn't the #jumpFalse need to know what > the literal to send is? I also don't understand how it would extract the > block contents. You don't need to change bytecode. Just by analysing that jump bytecode jumps over a block. Then you can assume that bytes between jump bytecode and byte where it points to is the block body. So, you can do the trick by changing implementation of #jumpFalse. By sending #IfTrue: message to receiver and checking the result. > > thanks, > Rob > > > ----- Original Message ----- > From: "Igor Stasenko" <[hidden email]> > To: "The general-purpose Squeak developers list" > <[hidden email]> > Sent: Thursday, October 18, 2007 3:06 PM > Subject: Re: runtime compiled method optimizations > > > > No, i think you'd better change the implementation of #jumpFalse > > bytecode. > > If you see that receiver is non-local , then simply do message send. > > And, i think you can safely use info from jump bytecode to extract > > block contents > > (bytes 19 - 22 is the block body). > > > > On 19/10/2007, Robert Withers <[hidden email]> wrote: > >> Hi all, > >> > >> I have a simple method containing an ifTrue: message. I have > >> compiled it normally, which uses macro transformations: > >> > >> 17 <10> pushTemp: 0 > >> 18 <9B> jumpFalse: 23 > >> 19 <10> pushTemp: 0 > >> 20 <20> pushConstant: 4 > >> 21 <B0> send: + > >> 22 <7C> returnTop > >> 23 <78> returnSelf > >> > >> and I have compiled it using Klaus Witzel's nifty compiler changes to > >> remove macro transformations and the result is an explicit message > >> send of #ifTrue: > >> > >> 21 <10> pushTemp: 0 > >> 22 <89> pushThisContext: > >> 23 <75> pushConstant: 0 > >> 24 <C8> send: blockCopy: > >> 25 <A4 04> jumpTo: 31 > >> 27 <10> pushTemp: 0 > >> 28 <21> pushConstant: 4 > >> 29 <B0> send: + > >> 30 <7C> returnTop > >> 31 <E0> send: ifTrue: > >> 32 <87> pop > >> 33 <78> returnSelf > >> > >> I would like to check the receiver of the ifTrue:, the 1st method arg > >> in this case (Temp: 0), to see if a certain situation exists (is it a > >> local reference to an object?). If it is true, I would like to run > >> the optimal code from the first example, instead of the longer second > >> example. How could we do that? Something like this? Could it be > >> done entirely by the compiler, given the existence of the bytecode > >> routine for #testLocalReference? > >> > >> 21 <10> pushTemp: 0 > >> 22 <??> testLocalReference > >> 23 <??> jumpFalse: 30 > >> 24 <10> pushTemp: 0 > >> 25 <??> jumpFalse: 40 > >> 26 <10> pushTemp: 0 > >> 27 <20> pushConstant: 4 > >> 28 <B0> send: + > >> 29 <7C> returnTop > >> 30 <89> pushThisContext: > >> 31 <75> pushConstant: 0 > >> 32 <C8> send: blockCopy: > >> 33 <?? ??> jumpTo: 38 > >> 34 <10> pushTemp: 0 > >> 35 <21> pushConstant: 4 > >> 36 <B0> send: + > >> 37 <7C> returnTop > >> 38 <E0> send: ifTrue: > >> 39 <87> pop > >> 40 <78> returnSelf > >> > >> > >> Thanks! > >> Rob > >> > >> > >> > > > > > > -- > > Best regards, > > Igor Stasenko AKA sig. > > > > > > > -- Best regards, Igor Stasenko AKA sig. |
----- Original Message ----- From: "Igor Stasenko" <[hidden email]> To: "The general-purpose Squeak developers list" <[hidden email]> Sent: Thursday, October 18, 2007 11:58 PM Subject: Re: runtime compiled method optimizations > On 19/10/2007, Rob Withers <[hidden email]> wrote: >> Igor, I'm afraid you've lost me. What would the bytecodes look like in >> your >> proposal? From what you've said, wouldn't the #jumpFalse need to know >> what >> the literal to send is? I also don't understand how it would extract the >> block contents. > > You don't need to change bytecode. Just by analysing that jump > bytecode jumps over a block. Then you can assume that bytes between > jump bytecode and byte where it points to is the block body. > So, you can do the trick by changing implementation of #jumpFalse. > By sending #IfTrue: message to receiver and checking the result. I'm still not getting it. I am all about getting this functionality in the most compact form. Are you saying that I should stick to the following bytecodes? 17 <10> pushTemp: 0 18 <9B> jumpFalse: 23 19 <10> pushTemp: 0 20 <20> pushConstant: 4 21 <B0> send: + 22 <7C> returnTop 23 <78> returnSelf Then if I am reading you right, the block is defined as PC start of block := the PC of the jumpFalse: + 1 PC end of block := the PC of the arg to the jumpBlock - 1 but I don't see where you setup and send the #blockCopy: I believe, but I am not sure, the #jumpFalse: is not only used for #ifTrue:, ifFalse:. ifTrue:ifFalse: and #ifFalse:ifTrue:, plus I want to be able to distinguish between these 4 methods. Unless they all get transformed to #ifTrue:ifFalse: with appropriate nil blocks... Still, I am having a hard time understanding how #jumpFalse: suddenly knows to test for boolean (better than the testLocalReference), then if it is not boolean, instead of sending mustBeBoolean, do a couple of block copies and send #ifTrue:ifFalse:. Can it do all that? Can we have it scan the bytecodes of the current method to make decisions about the boundaries of the block copies? Are we sure it should always send #ifTrue:ifFalse:? You raise some interesting questions. Rob > >> >> thanks, >> Rob >> >> >> ----- Original Message ----- >> From: "Igor Stasenko" <[hidden email]> >> To: "The general-purpose Squeak developers list" >> <[hidden email]> >> Sent: Thursday, October 18, 2007 3:06 PM >> Subject: Re: runtime compiled method optimizations >> >> >> > No, i think you'd better change the implementation of #jumpFalse >> > bytecode. >> > If you see that receiver is non-local , then simply do message send. >> > And, i think you can safely use info from jump bytecode to extract >> > block contents >> > (bytes 19 - 22 is the block body). >> > >> > On 19/10/2007, Robert Withers <[hidden email]> wrote: >> >> Hi all, >> >> >> >> I have a simple method containing an ifTrue: message. I have >> >> compiled it normally, which uses macro transformations: >> >> >> >> 17 <10> pushTemp: 0 >> >> 18 <9B> jumpFalse: 23 >> >> 19 <10> pushTemp: 0 >> >> 20 <20> pushConstant: 4 >> >> 21 <B0> send: + >> >> 22 <7C> returnTop >> >> 23 <78> returnSelf >> >> >> >> and I have compiled it using Klaus Witzel's nifty compiler changes to >> >> remove macro transformations and the result is an explicit message >> >> send of #ifTrue: >> >> >> >> 21 <10> pushTemp: 0 >> >> 22 <89> pushThisContext: >> >> 23 <75> pushConstant: 0 >> >> 24 <C8> send: blockCopy: >> >> 25 <A4 04> jumpTo: 31 >> >> 27 <10> pushTemp: 0 >> >> 28 <21> pushConstant: 4 >> >> 29 <B0> send: + >> >> 30 <7C> returnTop >> >> 31 <E0> send: ifTrue: >> >> 32 <87> pop >> >> 33 <78> returnSelf >> >> >> >> I would like to check the receiver of the ifTrue:, the 1st method arg >> >> in this case (Temp: 0), to see if a certain situation exists (is it a >> >> local reference to an object?). If it is true, I would like to run >> >> the optimal code from the first example, instead of the longer second >> >> example. How could we do that? Something like this? Could it be >> >> done entirely by the compiler, given the existence of the bytecode >> >> routine for #testLocalReference? >> >> >> >> 21 <10> pushTemp: 0 >> >> 22 <??> testLocalReference >> >> 23 <??> jumpFalse: 30 >> >> 24 <10> pushTemp: 0 >> >> 25 <??> jumpFalse: 40 >> >> 26 <10> pushTemp: 0 >> >> 27 <20> pushConstant: 4 >> >> 28 <B0> send: + >> >> 29 <7C> returnTop >> >> 30 <89> pushThisContext: >> >> 31 <75> pushConstant: 0 >> >> 32 <C8> send: blockCopy: >> >> 33 <?? ??> jumpTo: 38 >> >> 34 <10> pushTemp: 0 >> >> 35 <21> pushConstant: 4 >> >> 36 <B0> send: + >> >> 37 <7C> returnTop >> >> 38 <E0> send: ifTrue: >> >> 39 <87> pop >> >> 40 <78> returnSelf >> >> >> >> >> >> Thanks! >> >> Rob >> >> >> >> >> >> >> > >> > >> > -- >> > Best regards, >> > Igor Stasenko AKA sig. >> > >> > >> >> >> > > > -- > Best regards, > Igor Stasenko AKA sig. > > |
You will also have backward jumps generated by loops (to:do: whileTrue:
whileFalse:)... Though you might be able to transform all these jumps in equivalent message send (See Decompiler), that's might be impracticle to do that at interpreter level. Rob Withers a écrit : > > ----- Original Message ----- From: "Igor Stasenko" <[hidden email]> > To: "The general-purpose Squeak developers list" > <[hidden email]> > Sent: Thursday, October 18, 2007 11:58 PM > Subject: Re: runtime compiled method optimizations > > >> On 19/10/2007, Rob Withers <[hidden email]> wrote: >>> Igor, I'm afraid you've lost me. What would the bytecodes look like >>> in your >>> proposal? From what you've said, wouldn't the #jumpFalse need to >>> know what >>> the literal to send is? I also don't understand how it would extract >>> the >>> block contents. >> >> You don't need to change bytecode. Just by analysing that jump >> bytecode jumps over a block. Then you can assume that bytes between >> jump bytecode and byte where it points to is the block body. >> So, you can do the trick by changing implementation of #jumpFalse. >> By sending #IfTrue: message to receiver and checking the result. > > I'm still not getting it. I am all about getting this functionality in > the most compact form. Are you saying that I should stick to the > following bytecodes? > > 17 <10> pushTemp: 0 > 18 <9B> jumpFalse: 23 > 19 <10> pushTemp: 0 > 20 <20> pushConstant: 4 > 21 <B0> send: + > 22 <7C> returnTop > 23 <78> returnSelf > > Then if I am reading you right, the block is defined as > PC start of block := the PC of the jumpFalse: + 1 > PC end of block := the PC of the arg to the jumpBlock - 1 > but I don't see where you setup and send the #blockCopy: > > I believe, but I am not sure, the #jumpFalse: is not only used for > #ifTrue:, ifFalse:. ifTrue:ifFalse: and #ifFalse:ifTrue:, plus I want to > be able to distinguish between these 4 methods. Unless they all get > transformed to #ifTrue:ifFalse: with appropriate nil blocks... > > Still, I am having a hard time understanding how #jumpFalse: suddenly > knows to test for boolean (better than the testLocalReference), then if > it is not boolean, instead of sending mustBeBoolean, do a couple of > block copies and send #ifTrue:ifFalse:. Can it do all that? Can we > have it scan the bytecodes of the current method to make decisions about > the boundaries of the block copies? Are we sure it should always send > #ifTrue:ifFalse:? You raise some interesting questions. > > Rob > >> >>> >>> thanks, >>> Rob >>> >>> >>> ----- Original Message ----- >>> From: "Igor Stasenko" <[hidden email]> >>> To: "The general-purpose Squeak developers list" >>> <[hidden email]> >>> Sent: Thursday, October 18, 2007 3:06 PM >>> Subject: Re: runtime compiled method optimizations >>> >>> >>> > No, i think you'd better change the implementation of #jumpFalse >>> > bytecode. >>> > If you see that receiver is non-local , then simply do message send. >>> > And, i think you can safely use info from jump bytecode to extract >>> > block contents >>> > (bytes 19 - 22 is the block body). >>> > >>> > On 19/10/2007, Robert Withers <[hidden email]> wrote: >>> >> Hi all, >>> >> >>> >> I have a simple method containing an ifTrue: message. I have >>> >> compiled it normally, which uses macro transformations: >>> >> >>> >> 17 <10> pushTemp: 0 >>> >> 18 <9B> jumpFalse: 23 >>> >> 19 <10> pushTemp: 0 >>> >> 20 <20> pushConstant: 4 >>> >> 21 <B0> send: + >>> >> 22 <7C> returnTop >>> >> 23 <78> returnSelf >>> >> >>> >> and I have compiled it using Klaus Witzel's nifty compiler changes to >>> >> remove macro transformations and the result is an explicit message >>> >> send of #ifTrue: >>> >> >>> >> 21 <10> pushTemp: 0 >>> >> 22 <89> pushThisContext: >>> >> 23 <75> pushConstant: 0 >>> >> 24 <C8> send: blockCopy: >>> >> 25 <A4 04> jumpTo: 31 >>> >> 27 <10> pushTemp: 0 >>> >> 28 <21> pushConstant: 4 >>> >> 29 <B0> send: + >>> >> 30 <7C> returnTop >>> >> 31 <E0> send: ifTrue: >>> >> 32 <87> pop >>> >> 33 <78> returnSelf >>> >> >>> >> I would like to check the receiver of the ifTrue:, the 1st method arg >>> >> in this case (Temp: 0), to see if a certain situation exists (is it a >>> >> local reference to an object?). If it is true, I would like to run >>> >> the optimal code from the first example, instead of the longer second >>> >> example. How could we do that? Something like this? Could it be >>> >> done entirely by the compiler, given the existence of the bytecode >>> >> routine for #testLocalReference? >>> >> >>> >> 21 <10> pushTemp: 0 >>> >> 22 <??> testLocalReference >>> >> 23 <??> jumpFalse: 30 >>> >> 24 <10> pushTemp: 0 >>> >> 25 <??> jumpFalse: 40 >>> >> 26 <10> pushTemp: 0 >>> >> 27 <20> pushConstant: 4 >>> >> 28 <B0> send: + >>> >> 29 <7C> returnTop >>> >> 30 <89> pushThisContext: >>> >> 31 <75> pushConstant: 0 >>> >> 32 <C8> send: blockCopy: >>> >> 33 <?? ??> jumpTo: 38 >>> >> 34 <10> pushTemp: 0 >>> >> 35 <21> pushConstant: 4 >>> >> 36 <B0> send: + >>> >> 37 <7C> returnTop >>> >> 38 <E0> send: ifTrue: >>> >> 39 <87> pop >>> >> 40 <78> returnSelf >>> >> >>> >> >>> >> Thanks! >>> >> Rob >>> >> >>> >> >>> >> >>> > >>> > >>> > -- >>> > Best regards, >>> > Igor Stasenko AKA sig. >>> > >>> > >>> >>> >>> >> >> >> -- >> Best regards, >> Igor Stasenko AKA sig. >> >> > > > |
That's it, the backward jumps use jumpFalse: and jumpTrue:. It rings a
bell. I am trying to transform these jumps to equivalent msg sends, only when the receiver is not the expected type. This way, the normal fast transform works most of the time and when it is the wrong receiver we get a msg send in the image that I can intercept. The best of both worlds. Unfortunately it more than doubles the bytecodes for these composite constructs, so I'd love to figure out the most compact forms. Perhaps the way to go is to define bytecodes for all combinations like jumpFalseForIfTrue: jumpFalseForIfFalse: jumpFalseForIfTrueIfFalse: jumpFalseForWhileFalse: jumpTrueForWhileTrue: jumpFalseForToDo: and so on. Then I would need to figure out how to capture the blocks. Rob ----- Original Message ----- From: "nicolas cellier" <[hidden email]> To: <[hidden email]> Sent: Friday, October 19, 2007 12:17 PM Subject: Re: runtime compiled method optimizations > You will also have backward jumps generated by loops (to:do: whileTrue: > whileFalse:)... > > Though you might be able to transform all these jumps in equivalent > message send (See Decompiler), that's might be impracticle to do that at > interpreter level. > > > Rob Withers a écrit : >> >> ----- Original Message ----- From: "Igor Stasenko" <[hidden email]> >> To: "The general-purpose Squeak developers list" >> <[hidden email]> >> Sent: Thursday, October 18, 2007 11:58 PM >> Subject: Re: runtime compiled method optimizations >> >> >>> On 19/10/2007, Rob Withers <[hidden email]> wrote: >>>> Igor, I'm afraid you've lost me. What would the bytecodes look like in >>>> your >>>> proposal? From what you've said, wouldn't the #jumpFalse need to know >>>> what >>>> the literal to send is? I also don't understand how it would extract >>>> the >>>> block contents. >>> >>> You don't need to change bytecode. Just by analysing that jump >>> bytecode jumps over a block. Then you can assume that bytes between >>> jump bytecode and byte where it points to is the block body. >>> So, you can do the trick by changing implementation of #jumpFalse. >>> By sending #IfTrue: message to receiver and checking the result. >> >> I'm still not getting it. I am all about getting this functionality in >> the most compact form. Are you saying that I should stick to the >> following bytecodes? >> >> 17 <10> pushTemp: 0 >> 18 <9B> jumpFalse: 23 >> 19 <10> pushTemp: 0 >> 20 <20> pushConstant: 4 >> 21 <B0> send: + >> 22 <7C> returnTop >> 23 <78> returnSelf >> >> Then if I am reading you right, the block is defined as >> PC start of block := the PC of the jumpFalse: + 1 >> PC end of block := the PC of the arg to the jumpBlock - 1 >> but I don't see where you setup and send the #blockCopy: >> >> I believe, but I am not sure, the #jumpFalse: is not only used for >> #ifTrue:, ifFalse:. ifTrue:ifFalse: and #ifFalse:ifTrue:, plus I want to >> be able to distinguish between these 4 methods. Unless they all get >> transformed to #ifTrue:ifFalse: with appropriate nil blocks... >> >> Still, I am having a hard time understanding how #jumpFalse: suddenly >> knows to test for boolean (better than the testLocalReference), then if >> it is not boolean, instead of sending mustBeBoolean, do a couple of block >> copies and send #ifTrue:ifFalse:. Can it do all that? Can we have it >> scan the bytecodes of the current method to make decisions about the >> boundaries of the block copies? Are we sure it should always send >> #ifTrue:ifFalse:? You raise some interesting questions. >> >> Rob >> >>> >>>> >>>> thanks, >>>> Rob >>>> >>>> >>>> ----- Original Message ----- >>>> From: "Igor Stasenko" <[hidden email]> >>>> To: "The general-purpose Squeak developers list" >>>> <[hidden email]> >>>> Sent: Thursday, October 18, 2007 3:06 PM >>>> Subject: Re: runtime compiled method optimizations >>>> >>>> >>>> > No, i think you'd better change the implementation of #jumpFalse >>>> > bytecode. >>>> > If you see that receiver is non-local , then simply do message send. >>>> > And, i think you can safely use info from jump bytecode to extract >>>> > block contents >>>> > (bytes 19 - 22 is the block body). >>>> > >>>> > On 19/10/2007, Robert Withers <[hidden email]> wrote: >>>> >> Hi all, >>>> >> >>>> >> I have a simple method containing an ifTrue: message. I have >>>> >> compiled it normally, which uses macro transformations: >>>> >> >>>> >> 17 <10> pushTemp: 0 >>>> >> 18 <9B> jumpFalse: 23 >>>> >> 19 <10> pushTemp: 0 >>>> >> 20 <20> pushConstant: 4 >>>> >> 21 <B0> send: + >>>> >> 22 <7C> returnTop >>>> >> 23 <78> returnSelf >>>> >> >>>> >> and I have compiled it using Klaus Witzel's nifty compiler changes >>>> >> to >>>> >> remove macro transformations and the result is an explicit message >>>> >> send of #ifTrue: >>>> >> >>>> >> 21 <10> pushTemp: 0 >>>> >> 22 <89> pushThisContext: >>>> >> 23 <75> pushConstant: 0 >>>> >> 24 <C8> send: blockCopy: >>>> >> 25 <A4 04> jumpTo: 31 >>>> >> 27 <10> pushTemp: 0 >>>> >> 28 <21> pushConstant: 4 >>>> >> 29 <B0> send: + >>>> >> 30 <7C> returnTop >>>> >> 31 <E0> send: ifTrue: >>>> >> 32 <87> pop >>>> >> 33 <78> returnSelf >>>> >> >>>> >> I would like to check the receiver of the ifTrue:, the 1st method >>>> >> arg >>>> >> in this case (Temp: 0), to see if a certain situation exists (is it >>>> >> a >>>> >> local reference to an object?). If it is true, I would like to run >>>> >> the optimal code from the first example, instead of the longer >>>> >> second >>>> >> example. How could we do that? Something like this? Could it be >>>> >> done entirely by the compiler, given the existence of the bytecode >>>> >> routine for #testLocalReference? >>>> >> >>>> >> 21 <10> pushTemp: 0 >>>> >> 22 <??> testLocalReference >>>> >> 23 <??> jumpFalse: 30 >>>> >> 24 <10> pushTemp: 0 >>>> >> 25 <??> jumpFalse: 40 >>>> >> 26 <10> pushTemp: 0 >>>> >> 27 <20> pushConstant: 4 >>>> >> 28 <B0> send: + >>>> >> 29 <7C> returnTop >>>> >> 30 <89> pushThisContext: >>>> >> 31 <75> pushConstant: 0 >>>> >> 32 <C8> send: blockCopy: >>>> >> 33 <?? ??> jumpTo: 38 >>>> >> 34 <10> pushTemp: 0 >>>> >> 35 <21> pushConstant: 4 >>>> >> 36 <B0> send: + >>>> >> 37 <7C> returnTop >>>> >> 38 <E0> send: ifTrue: >>>> >> 39 <87> pop >>>> >> 40 <78> returnSelf >>>> >> >>>> >> >>>> >> Thanks! >>>> >> Rob >>>> >> >>>> >> >>>> >> >>>> > >>>> > >>>> > -- >>>> > Best regards, >>>> > Igor Stasenko AKA sig. >>>> > >>>> > >>>> >>>> >>>> >>> >>> >>> -- >>> Best regards, >>> Igor Stasenko AKA sig. >>> >>> >> >> >> > > > |
But you can do somethings like:
exp isLocalReference ifTrue:[exp perform: #ifTrue:ifFalse: with: ... with: ....] ifFalse: [...] Mth On Oct 19, 2007, at 9:32 PM, Rob Withers wrote: > That's it, the backward jumps use jumpFalse: and jumpTrue:. It > rings a bell. > > I am trying to transform these jumps to equivalent msg sends, only > when the receiver is not the expected type. This way, the normal > fast transform works most of the time and when it is the wrong > receiver we get a msg send in the image that I can intercept. The > best of both worlds. Unfortunately it more than doubles the > bytecodes for these composite constructs, so I'd love to figure out > the most compact forms. > > Perhaps the way to go is to define bytecodes for all combinations like > jumpFalseForIfTrue: > jumpFalseForIfFalse: > jumpFalseForIfTrueIfFalse: > jumpFalseForWhileFalse: > jumpTrueForWhileTrue: > jumpFalseForToDo: > and so on. Then I would need to figure out how to capture the blocks. > > Rob > > ----- Original Message ----- From: "nicolas cellier" > <[hidden email]> > To: <[hidden email]> > Sent: Friday, October 19, 2007 12:17 PM > Subject: Re: runtime compiled method optimizations > > >> You will also have backward jumps generated by loops (to:do: >> whileTrue: whileFalse:)... >> >> Though you might be able to transform all these jumps in >> equivalent message send (See Decompiler), that's might be >> impracticle to do that at interpreter level. >> >> >> Rob Withers a écrit : >>> >>> ----- Original Message ----- From: "Igor Stasenko" >>> <[hidden email]> >>> To: "The general-purpose Squeak developers list" <squeak- >>> [hidden email]> >>> Sent: Thursday, October 18, 2007 11:58 PM >>> Subject: Re: runtime compiled method optimizations >>> >>> >>>> On 19/10/2007, Rob Withers <[hidden email]> wrote: >>>>> Igor, I'm afraid you've lost me. What would the bytecodes look >>>>> like in your >>>>> proposal? From what you've said, wouldn't the #jumpFalse need >>>>> to know what >>>>> the literal to send is? I also don't understand how it would >>>>> extract the >>>>> block contents. >>>> >>>> You don't need to change bytecode. Just by analysing that jump >>>> bytecode jumps over a block. Then you can assume that bytes between >>>> jump bytecode and byte where it points to is the block body. >>>> So, you can do the trick by changing implementation of #jumpFalse. >>>> By sending #IfTrue: message to receiver and checking the result. >>> >>> I'm still not getting it. I am all about getting this >>> functionality in the most compact form. Are you saying that I >>> should stick to the following bytecodes? >>> >>> 17 <10> pushTemp: 0 >>> 18 <9B> jumpFalse: 23 >>> 19 <10> pushTemp: 0 >>> 20 <20> pushConstant: 4 >>> 21 <B0> send: + >>> 22 <7C> returnTop >>> 23 <78> returnSelf >>> >>> Then if I am reading you right, the block is defined as >>> PC start of block := the PC of the jumpFalse: + 1 >>> PC end of block := the PC of the arg to the jumpBlock - 1 >>> but I don't see where you setup and send the #blockCopy: >>> >>> I believe, but I am not sure, the #jumpFalse: is not only used >>> for #ifTrue:, ifFalse:. ifTrue:ifFalse: and #ifFalse:ifTrue:, >>> plus I want to be able to distinguish between these 4 methods. >>> Unless they all get transformed to #ifTrue:ifFalse: with >>> appropriate nil blocks... >>> >>> Still, I am having a hard time understanding how #jumpFalse: >>> suddenly knows to test for boolean (better than the >>> testLocalReference), then if it is not boolean, instead of >>> sending mustBeBoolean, do a couple of block copies and send >>> #ifTrue:ifFalse:. Can it do all that? Can we have it scan the >>> bytecodes of the current method to make decisions about the >>> boundaries of the block copies? Are we sure it should always >>> send #ifTrue:ifFalse:? You raise some interesting questions. >>> >>> Rob >>> >>>> >>>>> >>>>> thanks, >>>>> Rob >>>>> >>>>> >>>>> ----- Original Message ----- >>>>> From: "Igor Stasenko" <[hidden email]> >>>>> To: "The general-purpose Squeak developers list" >>>>> <[hidden email]> >>>>> Sent: Thursday, October 18, 2007 3:06 PM >>>>> Subject: Re: runtime compiled method optimizations >>>>> >>>>> >>>>> > No, i think you'd better change the implementation of #jumpFalse >>>>> > bytecode. >>>>> > If you see that receiver is non-local , then simply do >>>>> message send. >>>>> > And, i think you can safely use info from jump bytecode to >>>>> extract >>>>> > block contents >>>>> > (bytes 19 - 22 is the block body). >>>>> > >>>>> > On 19/10/2007, Robert Withers <[hidden email]> wrote: >>>>> >> Hi all, >>>>> >> >>>>> >> I have a simple method containing an ifTrue: message. I have >>>>> >> compiled it normally, which uses macro transformations: >>>>> >> >>>>> >> 17 <10> pushTemp: 0 >>>>> >> 18 <9B> jumpFalse: 23 >>>>> >> 19 <10> pushTemp: 0 >>>>> >> 20 <20> pushConstant: 4 >>>>> >> 21 <B0> send: + >>>>> >> 22 <7C> returnTop >>>>> >> 23 <78> returnSelf >>>>> >> >>>>> >> and I have compiled it using Klaus Witzel's nifty compiler >>>>> changes >> to >>>>> >> remove macro transformations and the result is an explicit >>>>> message >>>>> >> send of #ifTrue: >>>>> >> >>>>> >> 21 <10> pushTemp: 0 >>>>> >> 22 <89> pushThisContext: >>>>> >> 23 <75> pushConstant: 0 >>>>> >> 24 <C8> send: blockCopy: >>>>> >> 25 <A4 04> jumpTo: 31 >>>>> >> 27 <10> pushTemp: 0 >>>>> >> 28 <21> pushConstant: 4 >>>>> >> 29 <B0> send: + >>>>> >> 30 <7C> returnTop >>>>> >> 31 <E0> send: ifTrue: >>>>> >> 32 <87> pop >>>>> >> 33 <78> returnSelf >>>>> >> >>>>> >> I would like to check the receiver of the ifTrue:, the 1st >>>>> method >> arg >>>>> >> in this case (Temp: 0), to see if a certain situation exists >>>>> (is it >> a >>>>> >> local reference to an object?). If it is true, I would like >>>>> to run >>>>> >> the optimal code from the first example, instead of the >>>>> longer >> second >>>>> >> example. How could we do that? Something like this? >>>>> Could it be >>>>> >> done entirely by the compiler, given the existence of the >>>>> bytecode >>>>> >> routine for #testLocalReference? >>>>> >> >>>>> >> 21 <10> pushTemp: 0 >>>>> >> 22 <??> testLocalReference >>>>> >> 23 <??> jumpFalse: 30 >>>>> >> 24 <10> pushTemp: 0 >>>>> >> 25 <??> jumpFalse: 40 >>>>> >> 26 <10> pushTemp: 0 >>>>> >> 27 <20> pushConstant: 4 >>>>> >> 28 <B0> send: + >>>>> >> 29 <7C> returnTop >>>>> >> 30 <89> pushThisContext: >>>>> >> 31 <75> pushConstant: 0 >>>>> >> 32 <C8> send: blockCopy: >>>>> >> 33 <?? ??> jumpTo: 38 >>>>> >> 34 <10> pushTemp: 0 >>>>> >> 35 <21> pushConstant: 4 >>>>> >> 36 <B0> send: + >>>>> >> 37 <7C> returnTop >>>>> >> 38 <E0> send: ifTrue: >>>>> >> 39 <87> pop >>>>> >> 40 <78> returnSelf >>>>> >> >>>>> >> >>>>> >> Thanks! >>>>> >> Rob >>>>> >> >>>>> >> >>>>> >> >>>>> > >>>>> > >>>>> > -- >>>>> > Best regards, >>>>> > Igor Stasenko AKA sig. >>>>> > >>>>> > >>>>> >>>>> >>>>> >>>> >>>> >>>> -- >>>> Best regards, >>>> Igor Stasenko AKA sig. >>>> >>>> >>> >>> >>> >> >> > > |
In reply to this post by Rob Withers
Rob,
As I gather, it is more experimental and performance concern comes later, right? If so, I'd forget about bytecodes and stuff, and write your own Smalltalk parser first. The parser creates a parse tree (not ParseNode kind but almost just nested arrays). You do analysis and transformation of the tree and convert the result to bunch of methods in whatever way you would like. For a selector like #+, you just translate it to some other selector and don't have to worry about bytecode. OMeta package on SqueakMap and an Smalltalk implementation example in MMeta package on SqueakMap might help you. It is a few hundreds of lines code so not hard to learn and change. Stay at higher level whenever possible. Just a thought, -- Yoshiki At Fri, 19 Oct 2007 12:32:30 -0700, Rob Withers wrote: > > That's it, the backward jumps use jumpFalse: and jumpTrue:. It rings a > bell. > > I am trying to transform these jumps to equivalent msg sends, only when the > receiver is not the expected type. This way, the normal fast transform > works most of the time and when it is the wrong receiver we get a msg send > in the image that I can intercept. The best of both worlds. Unfortunately > it more than doubles the bytecodes for these composite constructs, so I'd > love to figure out the most compact forms. > > Perhaps the way to go is to define bytecodes for all combinations like > jumpFalseForIfTrue: > jumpFalseForIfFalse: > jumpFalseForIfTrueIfFalse: > jumpFalseForWhileFalse: > jumpTrueForWhileTrue: > jumpFalseForToDo: > and so on. Then I would need to figure out how to capture the blocks. > > Rob > > ----- Original Message ----- > From: "nicolas cellier" <[hidden email]> > To: <[hidden email]> > Sent: Friday, October 19, 2007 12:17 PM > Subject: Re: runtime compiled method optimizations > > > > You will also have backward jumps generated by loops (to:do: whileTrue: > > whileFalse:)... > > > > Though you might be able to transform all these jumps in equivalent > > message send (See Decompiler), that's might be impracticle to do that at > > interpreter level. > > > > > > Rob Withers a écrit : > >> > >> ----- Original Message ----- From: "Igor Stasenko" <[hidden email]> > >> To: "The general-purpose Squeak developers list" > >> <[hidden email]> > >> Sent: Thursday, October 18, 2007 11:58 PM > >> Subject: Re: runtime compiled method optimizations > >> > >> > >>> On 19/10/2007, Rob Withers <[hidden email]> wrote: > >>>> Igor, I'm afraid you've lost me. What would the bytecodes look like in > >>>> your > >>>> proposal? From what you've said, wouldn't the #jumpFalse need to know > >>>> what > >>>> the literal to send is? I also don't understand how it would extract > >>>> the > >>>> block contents. > >>> > >>> You don't need to change bytecode. Just by analysing that jump > >>> bytecode jumps over a block. Then you can assume that bytes between > >>> jump bytecode and byte where it points to is the block body. > >>> So, you can do the trick by changing implementation of #jumpFalse. > >>> By sending #IfTrue: message to receiver and checking the result. > >> > >> I'm still not getting it. I am all about getting this functionality in > >> the most compact form. Are you saying that I should stick to the > >> following bytecodes? > >> > >> 17 <10> pushTemp: 0 > >> 18 <9B> jumpFalse: 23 > >> 19 <10> pushTemp: 0 > >> 20 <20> pushConstant: 4 > >> 21 <B0> send: + > >> 22 <7C> returnTop > >> 23 <78> returnSelf > >> > >> Then if I am reading you right, the block is defined as > >> PC start of block := the PC of the jumpFalse: + 1 > >> PC end of block := the PC of the arg to the jumpBlock - 1 > >> but I don't see where you setup and send the #blockCopy: > >> > >> I believe, but I am not sure, the #jumpFalse: is not only used for > >> #ifTrue:, ifFalse:. ifTrue:ifFalse: and #ifFalse:ifTrue:, plus I want to > >> be able to distinguish between these 4 methods. Unless they all get > >> transformed to #ifTrue:ifFalse: with appropriate nil blocks... > >> > >> Still, I am having a hard time understanding how #jumpFalse: suddenly > >> knows to test for boolean (better than the testLocalReference), then if > >> it is not boolean, instead of sending mustBeBoolean, do a couple of block > >> copies and send #ifTrue:ifFalse:. Can it do all that? Can we have it > >> scan the bytecodes of the current method to make decisions about the > >> boundaries of the block copies? Are we sure it should always send > >> #ifTrue:ifFalse:? You raise some interesting questions. > >> > >> Rob > >> > >>> > >>>> > >>>> thanks, > >>>> Rob > >>>> > >>>> > >>>> ----- Original Message ----- > >>>> From: "Igor Stasenko" <[hidden email]> > >>>> To: "The general-purpose Squeak developers list" > >>>> <[hidden email]> > >>>> Sent: Thursday, October 18, 2007 3:06 PM > >>>> Subject: Re: runtime compiled method optimizations > >>>> > >>>> > >>>> > No, i think you'd better change the implementation of #jumpFalse > >>>> > bytecode. > >>>> > If you see that receiver is non-local , then simply do message send. > >>>> > And, i think you can safely use info from jump bytecode to extract > >>>> > block contents > >>>> > (bytes 19 - 22 is the block body). > >>>> > > >>>> > On 19/10/2007, Robert Withers <[hidden email]> wrote: > >>>> >> Hi all, > >>>> >> > >>>> >> I have a simple method containing an ifTrue: message. I have > >>>> >> compiled it normally, which uses macro transformations: > >>>> >> > >>>> >> 17 <10> pushTemp: 0 > >>>> >> 18 <9B> jumpFalse: 23 > >>>> >> 19 <10> pushTemp: 0 > >>>> >> 20 <20> pushConstant: 4 > >>>> >> 21 <B0> send: + > >>>> >> 22 <7C> returnTop > >>>> >> 23 <78> returnSelf > >>>> >> > >>>> >> and I have compiled it using Klaus Witzel's nifty compiler changes > >>>> >> to > >>>> >> remove macro transformations and the result is an explicit message > >>>> >> send of #ifTrue: > >>>> >> > >>>> >> 21 <10> pushTemp: 0 > >>>> >> 22 <89> pushThisContext: > >>>> >> 23 <75> pushConstant: 0 > >>>> >> 24 <C8> send: blockCopy: > >>>> >> 25 <A4 04> jumpTo: 31 > >>>> >> 27 <10> pushTemp: 0 > >>>> >> 28 <21> pushConstant: 4 > >>>> >> 29 <B0> send: + > >>>> >> 30 <7C> returnTop > >>>> >> 31 <E0> send: ifTrue: > >>>> >> 32 <87> pop > >>>> >> 33 <78> returnSelf > >>>> >> > >>>> >> I would like to check the receiver of the ifTrue:, the 1st method > >>>> >> arg > >>>> >> in this case (Temp: 0), to see if a certain situation exists (is it > >>>> >> a > >>>> >> local reference to an object?). If it is true, I would like to run > >>>> >> the optimal code from the first example, instead of the longer > >>>> >> second > >>>> >> example. How could we do that? Something like this? Could it be > >>>> >> done entirely by the compiler, given the existence of the bytecode > >>>> >> routine for #testLocalReference? > >>>> >> > >>>> >> 21 <10> pushTemp: 0 > >>>> >> 22 <??> testLocalReference > >>>> >> 23 <??> jumpFalse: 30 > >>>> >> 24 <10> pushTemp: 0 > >>>> >> 25 <??> jumpFalse: 40 > >>>> >> 26 <10> pushTemp: 0 > >>>> >> 27 <20> pushConstant: 4 > >>>> >> 28 <B0> send: + > >>>> >> 29 <7C> returnTop > >>>> >> 30 <89> pushThisContext: > >>>> >> 31 <75> pushConstant: 0 > >>>> >> 32 <C8> send: blockCopy: > >>>> >> 33 <?? ??> jumpTo: 38 > >>>> >> 34 <10> pushTemp: 0 > >>>> >> 35 <21> pushConstant: 4 > >>>> >> 36 <B0> send: + > >>>> >> 37 <7C> returnTop > >>>> >> 38 <E0> send: ifTrue: > >>>> >> 39 <87> pop > >>>> >> 40 <78> returnSelf > >>>> >> > >>>> >> > >>>> >> Thanks! > >>>> >> Rob > >>>> >> > >>>> >> > >>>> >> > >>>> > > >>>> > > >>>> > -- > >>>> > Best regards, > >>>> > Igor Stasenko AKA sig. > >>>> > > >>>> > > >>>> > >>>> > >>>> > >>> > >>> > >>> -- > >>> Best regards, > >>> Igor Stasenko AKA sig. > >>> > >>> > >> > >> > >> > > > > > > > > |
Thank you, Yoshiki, for your advice. I'll take a look at those packages.
One thing, I am trying to change the bytecodes that the Compiler generates for #ifTrue:, for example. I want to recompile the entire system to use these. This way I can get msg sends from anywhere when I need them (receiver is not a boolean). To do this, I need to add 4 bytecode routines to the interpreter, so don't use these bytecodes at home! But you can generate them to see what they look like. In addition to adding 4 routines to the interpreter, I also need to make the new MessageNodes bulletproof with respect to decompiling, before I make them part of the Compiler. Here are the samples that are macro transformed. After loading the attached changeset, run them to see the CompiledMethods generated. (ConditionalTransformCompiler compile: 'true ifTrue: [4+2]') method. (ConditionalTransformCompiler compile: 'false ifFalse: [4+2]') method. (ConditionalTransformCompiler compile: 'true ifTrue: [4+2] ifFalse: [3+1]') method. (ConditionalTransformCompiler compile: 'true ifFalse: [3+1] ifTrue: [4+2]') method. (ConditionalTransformCompiler compile: 'true and: [4+2]') method. (ConditionalTransformCompiler compile: 'false or: [4+2]') method. (ConditionalTransformCompiler compile: '[true] whileTrue: [4+2]') method. (ConditionalTransformCompiler compile: '[false] whileFalse: [4+2]') method. (ConditionalTransformCompiler compile: '[true] whileTrue') method. (ConditionalTransformCompiler compile: '[false] whileFalse') method. (ConditionalTransformCompiler compile: '1 to: 5 do: [:idx | 4+2]') method. (ConditionalTransformCompiler compile: '1 to: 5 by: 2 do: [:idx | 4+2]') method. (ConditionalTransformCompiler compile: '1 caseOf: {[2+2]->[1]}') method. (ConditionalTransformCompiler compile: '1 caseOf: {[2]->[1]} otherwise: [0]') method. (ConditionalTransformCompiler compile: 'nil ifNil: [4+2]') method. (ConditionalTransformCompiler compile: '1 ifNotNil: [4+2]') method. (ConditionalTransformCompiler compile: 'nil ifNil: [4+2] ifNotNil: [3+1]') method. (ConditionalTransformCompiler compile: '1 ifNotNil: [4+2] ifNil: [3+1]') method. Cheers, Rob ----- Original Message ----- From: "Yoshiki Ohshima" <[hidden email]> To: "The general-purpose Squeak developerslist" <[hidden email]> Sent: Saturday, October 20, 2007 11:44 AM Subject: Re: runtime compiled method optimizations Rob, As I gather, it is more experimental and performance concern comes later, right? If so, I'd forget about bytecodes and stuff, and write your own Smalltalk parser first. The parser creates a parse tree (not ParseNode kind but almost just nested arrays). You do analysis and transformation of the tree and convert the result to bunch of methods in whatever way you would like. For a selector like #+, you just translate it to some other selector and don't have to worry about bytecode. OMeta package on SqueakMap and an Smalltalk implementation example in MMeta package on SqueakMap might help you. It is a few hundreds of lines code so not hard to learn and change. Stay at higher level whenever possible. Just a thought, -- Yoshiki At Fri, 19 Oct 2007 12:32:30 -0700, Rob Withers wrote: > > That's it, the backward jumps use jumpFalse: and jumpTrue:. It rings a > bell. > > I am trying to transform these jumps to equivalent msg sends, only when > the > receiver is not the expected type. This way, the normal fast transform > works most of the time and when it is the wrong receiver we get a msg send > in the image that I can intercept. The best of both worlds. > Unfortunately > it more than doubles the bytecodes for these composite constructs, so I'd > love to figure out the most compact forms. > > Perhaps the way to go is to define bytecodes for all combinations like > jumpFalseForIfTrue: > jumpFalseForIfFalse: > jumpFalseForIfTrueIfFalse: > jumpFalseForWhileFalse: > jumpTrueForWhileTrue: > jumpFalseForToDo: > and so on. Then I would need to figure out how to capture the blocks. > > Rob > > ----- Original Message ----- > From: "nicolas cellier" <[hidden email]> > To: <[hidden email]> > Sent: Friday, October 19, 2007 12:17 PM > Subject: Re: runtime compiled method optimizations > > > > You will also have backward jumps generated by loops (to:do: whileTrue: > > whileFalse:)... > > > > Though you might be able to transform all these jumps in equivalent > > message send (See Decompiler), that's might be impracticle to do that at > > interpreter level. > > > > > > Rob Withers a écrit : > >> > >> ----- Original Message ----- From: "Igor Stasenko" <[hidden email]> > >> To: "The general-purpose Squeak developers list" > >> <[hidden email]> > >> Sent: Thursday, October 18, 2007 11:58 PM > >> Subject: Re: runtime compiled method optimizations > >> > >> > >>> On 19/10/2007, Rob Withers <[hidden email]> wrote: > >>>> Igor, I'm afraid you've lost me. What would the bytecodes look like > >>>> in > >>>> your > >>>> proposal? From what you've said, wouldn't the #jumpFalse need to > >>>> know > >>>> what > >>>> the literal to send is? I also don't understand how it would extract > >>>> the > >>>> block contents. > >>> > >>> You don't need to change bytecode. Just by analysing that jump > >>> bytecode jumps over a block. Then you can assume that bytes between > >>> jump bytecode and byte where it points to is the block body. > >>> So, you can do the trick by changing implementation of #jumpFalse. > >>> By sending #IfTrue: message to receiver and checking the result. > >> > >> I'm still not getting it. I am all about getting this functionality in > >> the most compact form. Are you saying that I should stick to the > >> following bytecodes? > >> > >> 17 <10> pushTemp: 0 > >> 18 <9B> jumpFalse: 23 > >> 19 <10> pushTemp: 0 > >> 20 <20> pushConstant: 4 > >> 21 <B0> send: + > >> 22 <7C> returnTop > >> 23 <78> returnSelf > >> > >> Then if I am reading you right, the block is defined as > >> PC start of block := the PC of the jumpFalse: + 1 > >> PC end of block := the PC of the arg to the jumpBlock - 1 > >> but I don't see where you setup and send the #blockCopy: > >> > >> I believe, but I am not sure, the #jumpFalse: is not only used for > >> #ifTrue:, ifFalse:. ifTrue:ifFalse: and #ifFalse:ifTrue:, plus I want > >> to > >> be able to distinguish between these 4 methods. Unless they all get > >> transformed to #ifTrue:ifFalse: with appropriate nil blocks... > >> > >> Still, I am having a hard time understanding how #jumpFalse: suddenly > >> knows to test for boolean (better than the testLocalReference), then if > >> it is not boolean, instead of sending mustBeBoolean, do a couple of > >> block > >> copies and send #ifTrue:ifFalse:. Can it do all that? Can we have it > >> scan the bytecodes of the current method to make decisions about the > >> boundaries of the block copies? Are we sure it should always send > >> #ifTrue:ifFalse:? You raise some interesting questions. > >> > >> Rob > >> > >>> > >>>> > >>>> thanks, > >>>> Rob > >>>> > >>>> > >>>> ----- Original Message ----- > >>>> From: "Igor Stasenko" <[hidden email]> > >>>> To: "The general-purpose Squeak developers list" > >>>> <[hidden email]> > >>>> Sent: Thursday, October 18, 2007 3:06 PM > >>>> Subject: Re: runtime compiled method optimizations > >>>> > >>>> > >>>> > No, i think you'd better change the implementation of #jumpFalse > >>>> > bytecode. > >>>> > If you see that receiver is non-local , then simply do message > >>>> > send. > >>>> > And, i think you can safely use info from jump bytecode to extract > >>>> > block contents > >>>> > (bytes 19 - 22 is the block body). > >>>> > > >>>> > On 19/10/2007, Robert Withers <[hidden email]> wrote: > >>>> >> Hi all, > >>>> >> > >>>> >> I have a simple method containing an ifTrue: message. I have > >>>> >> compiled it normally, which uses macro transformations: > >>>> >> > >>>> >> 17 <10> pushTemp: 0 > >>>> >> 18 <9B> jumpFalse: 23 > >>>> >> 19 <10> pushTemp: 0 > >>>> >> 20 <20> pushConstant: 4 > >>>> >> 21 <B0> send: + > >>>> >> 22 <7C> returnTop > >>>> >> 23 <78> returnSelf > >>>> >> > >>>> >> and I have compiled it using Klaus Witzel's nifty compiler changes > >>>> >> to > >>>> >> remove macro transformations and the result is an explicit message > >>>> >> send of #ifTrue: > >>>> >> > >>>> >> 21 <10> pushTemp: 0 > >>>> >> 22 <89> pushThisContext: > >>>> >> 23 <75> pushConstant: 0 > >>>> >> 24 <C8> send: blockCopy: > >>>> >> 25 <A4 04> jumpTo: 31 > >>>> >> 27 <10> pushTemp: 0 > >>>> >> 28 <21> pushConstant: 4 > >>>> >> 29 <B0> send: + > >>>> >> 30 <7C> returnTop > >>>> >> 31 <E0> send: ifTrue: > >>>> >> 32 <87> pop > >>>> >> 33 <78> returnSelf > >>>> >> > >>>> >> I would like to check the receiver of the ifTrue:, the 1st method > >>>> >> arg > >>>> >> in this case (Temp: 0), to see if a certain situation exists (is > >>>> >> it > >>>> >> a > >>>> >> local reference to an object?). If it is true, I would like to > >>>> >> run > >>>> >> the optimal code from the first example, instead of the longer > >>>> >> second > >>>> >> example. How could we do that? Something like this? Could it > >>>> >> be > >>>> >> done entirely by the compiler, given the existence of the bytecode > >>>> >> routine for #testLocalReference? > >>>> >> > >>>> >> 21 <10> pushTemp: 0 > >>>> >> 22 <??> testLocalReference > >>>> >> 23 <??> jumpFalse: 30 > >>>> >> 24 <10> pushTemp: 0 > >>>> >> 25 <??> jumpFalse: 40 > >>>> >> 26 <10> pushTemp: 0 > >>>> >> 27 <20> pushConstant: 4 > >>>> >> 28 <B0> send: + > >>>> >> 29 <7C> returnTop > >>>> >> 30 <89> pushThisContext: > >>>> >> 31 <75> pushConstant: 0 > >>>> >> 32 <C8> send: blockCopy: > >>>> >> 33 <?? ??> jumpTo: 38 > >>>> >> 34 <10> pushTemp: 0 > >>>> >> 35 <21> pushConstant: 4 > >>>> >> 36 <B0> send: + > >>>> >> 37 <7C> returnTop > >>>> >> 38 <E0> send: ifTrue: > >>>> >> 39 <87> pop > >>>> >> 40 <78> returnSelf > >>>> >> > >>>> >> > >>>> >> Thanks! > >>>> >> Rob > >>>> >> > >>>> >> > >>>> >> > >>>> > > >>>> > > >>>> > -- > >>>> > Best regards, > >>>> > Igor Stasenko AKA sig. > >>>> > > >>>> > > >>>> > >>>> > >>>> > >>> > >>> > >>> -- > >>> Best regards, > >>> Igor Stasenko AKA sig. > >>> > >>> > >> > >> > >> > > > > > > > > ConditionalTransformCompiler.1.cs (42K) Download Attachment |
In reply to this post by Yoshiki Ohshima-2
Oops. I can't find either MMeta or OMeta on SqueakMap.
----- Original Message ----- From: "Yoshiki Ohshima" <[hidden email]> To: "The general-purpose Squeak developerslist" <[hidden email]> Sent: Saturday, October 20, 2007 11:44 AM Subject: Re: runtime compiled method optimizations Rob, As I gather, it is more experimental and performance concern comes later, right? If so, I'd forget about bytecodes and stuff, and write your own Smalltalk parser first. The parser creates a parse tree (not ParseNode kind but almost just nested arrays). You do analysis and transformation of the tree and convert the result to bunch of methods in whatever way you would like. For a selector like #+, you just translate it to some other selector and don't have to worry about bytecode. OMeta package on SqueakMap and an Smalltalk implementation example in MMeta package on SqueakMap might help you. It is a few hundreds of lines code so not hard to learn and change. Stay at higher level whenever possible. Just a thought, -- Yoshiki At Fri, 19 Oct 2007 12:32:30 -0700, Rob Withers wrote: > > That's it, the backward jumps use jumpFalse: and jumpTrue:. It rings a > bell. > > I am trying to transform these jumps to equivalent msg sends, only when > the > receiver is not the expected type. This way, the normal fast transform > works most of the time and when it is the wrong receiver we get a msg send > in the image that I can intercept. The best of both worlds. > Unfortunately > it more than doubles the bytecodes for these composite constructs, so I'd > love to figure out the most compact forms. > > Perhaps the way to go is to define bytecodes for all combinations like > jumpFalseForIfTrue: > jumpFalseForIfFalse: > jumpFalseForIfTrueIfFalse: > jumpFalseForWhileFalse: > jumpTrueForWhileTrue: > jumpFalseForToDo: > and so on. Then I would need to figure out how to capture the blocks. > > Rob > > ----- Original Message ----- > From: "nicolas cellier" <[hidden email]> > To: <[hidden email]> > Sent: Friday, October 19, 2007 12:17 PM > Subject: Re: runtime compiled method optimizations > > > > You will also have backward jumps generated by loops (to:do: whileTrue: > > whileFalse:)... > > > > Though you might be able to transform all these jumps in equivalent > > message send (See Decompiler), that's might be impracticle to do that at > > interpreter level. > > > > > > Rob Withers a écrit : > >> > >> ----- Original Message ----- From: "Igor Stasenko" <[hidden email]> > >> To: "The general-purpose Squeak developers list" > >> <[hidden email]> > >> Sent: Thursday, October 18, 2007 11:58 PM > >> Subject: Re: runtime compiled method optimizations > >> > >> > >>> On 19/10/2007, Rob Withers <[hidden email]> wrote: > >>>> Igor, I'm afraid you've lost me. What would the bytecodes look like > >>>> in > >>>> your > >>>> proposal? From what you've said, wouldn't the #jumpFalse need to > >>>> know > >>>> what > >>>> the literal to send is? I also don't understand how it would extract > >>>> the > >>>> block contents. > >>> > >>> You don't need to change bytecode. Just by analysing that jump > >>> bytecode jumps over a block. Then you can assume that bytes between > >>> jump bytecode and byte where it points to is the block body. > >>> So, you can do the trick by changing implementation of #jumpFalse. > >>> By sending #IfTrue: message to receiver and checking the result. > >> > >> I'm still not getting it. I am all about getting this functionality in > >> the most compact form. Are you saying that I should stick to the > >> following bytecodes? > >> > >> 17 <10> pushTemp: 0 > >> 18 <9B> jumpFalse: 23 > >> 19 <10> pushTemp: 0 > >> 20 <20> pushConstant: 4 > >> 21 <B0> send: + > >> 22 <7C> returnTop > >> 23 <78> returnSelf > >> > >> Then if I am reading you right, the block is defined as > >> PC start of block := the PC of the jumpFalse: + 1 > >> PC end of block := the PC of the arg to the jumpBlock - 1 > >> but I don't see where you setup and send the #blockCopy: > >> > >> I believe, but I am not sure, the #jumpFalse: is not only used for > >> #ifTrue:, ifFalse:. ifTrue:ifFalse: and #ifFalse:ifTrue:, plus I want > >> to > >> be able to distinguish between these 4 methods. Unless they all get > >> transformed to #ifTrue:ifFalse: with appropriate nil blocks... > >> > >> Still, I am having a hard time understanding how #jumpFalse: suddenly > >> knows to test for boolean (better than the testLocalReference), then if > >> it is not boolean, instead of sending mustBeBoolean, do a couple of > >> block > >> copies and send #ifTrue:ifFalse:. Can it do all that? Can we have it > >> scan the bytecodes of the current method to make decisions about the > >> boundaries of the block copies? Are we sure it should always send > >> #ifTrue:ifFalse:? You raise some interesting questions. > >> > >> Rob > >> > >>> > >>>> > >>>> thanks, > >>>> Rob > >>>> > >>>> > >>>> ----- Original Message ----- > >>>> From: "Igor Stasenko" <[hidden email]> > >>>> To: "The general-purpose Squeak developers list" > >>>> <[hidden email]> > >>>> Sent: Thursday, October 18, 2007 3:06 PM > >>>> Subject: Re: runtime compiled method optimizations > >>>> > >>>> > >>>> > No, i think you'd better change the implementation of #jumpFalse > >>>> > bytecode. > >>>> > If you see that receiver is non-local , then simply do message > >>>> > send. > >>>> > And, i think you can safely use info from jump bytecode to extract > >>>> > block contents > >>>> > (bytes 19 - 22 is the block body). > >>>> > > >>>> > On 19/10/2007, Robert Withers <[hidden email]> wrote: > >>>> >> Hi all, > >>>> >> > >>>> >> I have a simple method containing an ifTrue: message. I have > >>>> >> compiled it normally, which uses macro transformations: > >>>> >> > >>>> >> 17 <10> pushTemp: 0 > >>>> >> 18 <9B> jumpFalse: 23 > >>>> >> 19 <10> pushTemp: 0 > >>>> >> 20 <20> pushConstant: 4 > >>>> >> 21 <B0> send: + > >>>> >> 22 <7C> returnTop > >>>> >> 23 <78> returnSelf > >>>> >> > >>>> >> and I have compiled it using Klaus Witzel's nifty compiler changes > >>>> >> to > >>>> >> remove macro transformations and the result is an explicit message > >>>> >> send of #ifTrue: > >>>> >> > >>>> >> 21 <10> pushTemp: 0 > >>>> >> 22 <89> pushThisContext: > >>>> >> 23 <75> pushConstant: 0 > >>>> >> 24 <C8> send: blockCopy: > >>>> >> 25 <A4 04> jumpTo: 31 > >>>> >> 27 <10> pushTemp: 0 > >>>> >> 28 <21> pushConstant: 4 > >>>> >> 29 <B0> send: + > >>>> >> 30 <7C> returnTop > >>>> >> 31 <E0> send: ifTrue: > >>>> >> 32 <87> pop > >>>> >> 33 <78> returnSelf > >>>> >> > >>>> >> I would like to check the receiver of the ifTrue:, the 1st method > >>>> >> arg > >>>> >> in this case (Temp: 0), to see if a certain situation exists (is > >>>> >> it > >>>> >> a > >>>> >> local reference to an object?). If it is true, I would like to > >>>> >> run > >>>> >> the optimal code from the first example, instead of the longer > >>>> >> second > >>>> >> example. How could we do that? Something like this? Could it > >>>> >> be > >>>> >> done entirely by the compiler, given the existence of the bytecode > >>>> >> routine for #testLocalReference? > >>>> >> > >>>> >> 21 <10> pushTemp: 0 > >>>> >> 22 <??> testLocalReference > >>>> >> 23 <??> jumpFalse: 30 > >>>> >> 24 <10> pushTemp: 0 > >>>> >> 25 <??> jumpFalse: 40 > >>>> >> 26 <10> pushTemp: 0 > >>>> >> 27 <20> pushConstant: 4 > >>>> >> 28 <B0> send: + > >>>> >> 29 <7C> returnTop > >>>> >> 30 <89> pushThisContext: > >>>> >> 31 <75> pushConstant: 0 > >>>> >> 32 <C8> send: blockCopy: > >>>> >> 33 <?? ??> jumpTo: 38 > >>>> >> 34 <10> pushTemp: 0 > >>>> >> 35 <21> pushConstant: 4 > >>>> >> 36 <B0> send: + > >>>> >> 37 <7C> returnTop > >>>> >> 38 <E0> send: ifTrue: > >>>> >> 39 <87> pop > >>>> >> 40 <78> returnSelf > >>>> >> > >>>> >> > >>>> >> Thanks! > >>>> >> Rob > >>>> >> > >>>> >> > >>>> >> > >>>> > > >>>> > > >>>> > -- > >>>> > Best regards, > >>>> > Igor Stasenko AKA sig. > >>>> > > >>>> > > >>>> > >>>> > >>>> > >>> > >>> > >>> -- > >>> Best regards, > >>> Igor Stasenko AKA sig. > >>> > >>> > >> > >> > >> > > > > > > > > |
> Oops. I can't find either MMeta or OMeta on SqueakMap.
Sorry. From this page: http://map1.squeakfoundation.org/packagesbyname look for "Meta" for MMeta (http://map1.squeakfoundation.org/package/e3cdcb13-a408-49c8-9a97-5e9b8befa4ac) and OMeta (http://map1.squeakfoundation.org/package/dea7935d-2497-45df-936c-69f0daedd136). -- Yoshiki |
Free forum by Nabble | Edit this page |