I've just posted a new beta image at:
ftp://ftp.squeak.org/4.2/ This one does not have wrecked PackageInfo's, and has most (but not all) of the aesthetic changes for 4.2. The test suite is looking better: 'CompilerExceptionsTest>>#testUnusedVariable DecompilerTests>>#testDecompileLoopWithMovingLimit DecompilerTests>>#testDecompilerInClassesMAtoMM DecompilerTests>>#testDecompilerInClassesSNtoSZ ExceptionTests>>#testHandlerFromAction MCPackageTest>>#testUnload MirrorPrimitiveTests>>#testMirrorAt MirrorPrimitiveTests>>#testMirrorInstVarAt MorphicUIBugTest>>#testShowAllBinParts ProcessTest>>#testAtomicSuspend SMDependencyTest>>#test2 StandardSystemFontsTest>>#testRestoreDefaultFonts ' We must be getting close. We could use help in fixing some of these final tests, or otherwise testing on your own applications. Thanks, Chris |
On Wed, 12 Jan 2011, Chris Muller wrote:
> I've just posted a new beta image at: > > ftp://ftp.squeak.org/4.2/ > > This one does not have wrecked PackageInfo's, and has most (but not > all) of the aesthetic changes for 4.2. > > The test suite is looking better: > > 'CompilerExceptionsTest>>#testUnusedVariable This one is new, I'd be happy if someone could have a look at it. > DecompilerTests>>#testDecompileLoopWithMovingLimit This is hard to fix, maybe impossible. > DecompilerTests>>#testDecompilerInClassesMAtoMM > DecompilerTests>>#testDecompilerInClassesSNtoSZ There are fixes in the Inbox for these 2, I'll integrate them soon. > ExceptionTests>>#testHandlerFromAction Also a new one. We probably won't fix it in this release. > MCPackageTest>>#testUnload This one is failing randomly. It would be nice if we could save the stack trace when it's failing. > MirrorPrimitiveTests>>#testMirrorAt > MirrorPrimitiveTests>>#testMirrorInstVarAt These are VM related unexpected passes. For some reason these two are passing with SqueakVM 4.0.2. > MorphicUIBugTest>>#testShowAllBinParts Random. > ProcessTest>>#testAtomicSuspend New one. I guess it's VM related. > SMDependencyTest>>#test2 Random. > StandardSystemFontsTest>>#testRestoreDefaultFonts Random. So we have: 4 that fail randomly 3 VM related 3 waiting to be fixed 2 fixed So in the end we shouldn't have more than 3. :) Levente > ' > > We must be getting close. We could use help in fixing some of these > final tests, or otherwise testing on your own applications. > > Thanks, > Chris > > |
>> DecompilerTests>>#testDecompileLoopWithMovingLimit
> > This is hard to fix, maybe impossible. > Without a Debugger, I must admit it's not that easy. With a Debugger, just step into it... Nicolas |
On Wed, 12 Jan 2011, Nicolas Cellier wrote:
>>> DecompilerTests>>#testDecompileLoopWithMovingLimit >> >> This is hard to fix, maybe impossible. >> > > Without a Debugger, I must admit it's not that easy. > With a Debugger, just step into it... Well, I never tried it, but somehow got the impression that if you fix this, you'll break the decompilation of the #to:do: version of the loop. But that won't break, because in that case the loop won't be inlined. Levente > > Nicolas > > |
In reply to this post by Levente Uzonyi-2
2011/1/12 Levente Uzonyi <[hidden email]>:
> On Wed, 12 Jan 2011, Chris Muller wrote: > >> I've just posted a new beta image at: >> >> ftp://ftp.squeak.org/4.2/ >> >> This one does not have wrecked PackageInfo's, and has most (but not >> all) of the aesthetic changes for 4.2. >> >> The test suite is looking better: >> >> 'CompilerExceptionsTest>>#testUnusedVariable > > This one is new, I'd be happy if someone could have a look at it. > This is due to latest improvements from Eliot. Now the BlockNode have their own tempsMark (set by Parser>>#temporaryBlockVariablesFor:). The Parser only records top level tempsMark in Parser>>#temporaries. If you look at the code in Parser>>#removeUnusedTemps, you see some defensive programming ((tempsMark between: 1 and: str size) and: [(str at: tempsMark) = $|]) ifFalse: [^ self]. But hey, the top level does not have any tempsMark, so the method prematurely returns without checking for some unused in the blocks. self justTriedCompiling: 'griffle | | ^[ | goo | ]' andItCorrectlyRaised: UnusedVariable. Shall we remove the tempsMark protection ? Nicolas |
In reply to this post by Chris Muller-3
On 12.01.2011, at 21:11, Chris Muller wrote: > I've just posted a new beta image at: > > ftp://ftp.squeak.org/4.2/ Btw, this is the same as http://ftp.squeak.org/4.2/ and I for one find http more convenient than ftp nowadays ... - Bert - > This one does not have wrecked PackageInfo's, and has most (but not > all) of the aesthetic changes for 4.2. > > The test suite is looking better: > > 'CompilerExceptionsTest>>#testUnusedVariable > DecompilerTests>>#testDecompileLoopWithMovingLimit > DecompilerTests>>#testDecompilerInClassesMAtoMM > DecompilerTests>>#testDecompilerInClassesSNtoSZ > ExceptionTests>>#testHandlerFromAction > MCPackageTest>>#testUnload > MirrorPrimitiveTests>>#testMirrorAt > MirrorPrimitiveTests>>#testMirrorInstVarAt > MorphicUIBugTest>>#testShowAllBinParts > ProcessTest>>#testAtomicSuspend > SMDependencyTest>>#test2 > StandardSystemFontsTest>>#testRestoreDefaultFonts > ' > > We must be getting close. We could use help in fixing some of these > final tests, or otherwise testing on your own applications. > > Thanks, > Chris > |
In reply to this post by Nicolas Cellier
Follow up on unused temps :
Wanna play with temps ? Try this : testUnusedVariable self compiling: 'griffle | goo | ^nil' shouldRaise: UnusedVariable; compiling: 'griffle | | ^[ | goo | ]' shouldRaise: UnusedVariable; compiling: 'griffle | | [ | goo | goo := nil. goo] yourself. ^[ | goo | ]' shouldRaise: UnusedVariable; compiling: 'griffle | | [ | goo | ] yourself. ^[ | goo | goo := nil. goo]' shouldRaise: UnusedVariable What happens is that Parser.scopeTable has a single entry for 'goo'. Consequently, the last registered goo wins. In the 3rd case, the last goo is unused, so hasRef = false, so UnusedVariable is raised. In the 4th case, the last goo nowHasRef, and we don't get any UnusedVariable. Until we get a scopeTable mapping each temp of each block, we gonna live in trouble. Nicolas 2011/1/12 Nicolas Cellier <[hidden email]>: > 2011/1/12 Levente Uzonyi <[hidden email]>: >> On Wed, 12 Jan 2011, Chris Muller wrote: >> >>> I've just posted a new beta image at: >>> >>> ftp://ftp.squeak.org/4.2/ >>> >>> This one does not have wrecked PackageInfo's, and has most (but not >>> all) of the aesthetic changes for 4.2. >>> >>> The test suite is looking better: >>> >>> 'CompilerExceptionsTest>>#testUnusedVariable >> >> This one is new, I'd be happy if someone could have a look at it. >> > > This is due to latest improvements from Eliot. > Now the BlockNode have their own tempsMark (set by > Parser>>#temporaryBlockVariablesFor:). > The Parser only records top level tempsMark in Parser>>#temporaries. > > If you look at the code in Parser>>#removeUnusedTemps, you see some > defensive programming > ((tempsMark between: 1 and: str size) > and: [(str at: tempsMark) = $|]) ifFalse: [^ self]. > > But hey, the top level does not have any tempsMark, so the method > prematurely returns without checking for some unused in the blocks. > self > justTriedCompiling: 'griffle | | ^[ | goo | ]' > andItCorrectlyRaised: UnusedVariable. > > Shall we remove the tempsMark protection ? > > Nicolas > |
Here's another decompiler problem that I actually ran into in production code. When decompiling this method, either the block-local temp should remain block-local, or one of the vars needs to be renamed:
blockLocalsAndArgs | product | product := 1. 1 to: 2 do: [:i | i = 1 ifTrue: [ | factor | factor := 6. product := product * factor ] ifFalse: [ #(9) do: [:factor | product := product * factor ] ] ]. ^ product = 13r42 This works fine if decompiled without temps but the standard in Squeak is to use the actual temp names - just accept this as a method and switch to decompiled view. The best fix might be if the decompiler always declared the variables in the inner-most block possible. Maybe moving the declarations is not even that hard to do as a post-process on the AST? - Bert - On 13.01.2011, at 00:51, Nicolas Cellier wrote: > Follow up on unused temps : > > Wanna play with temps ? Try this : > > testUnusedVariable > self > compiling: 'griffle | goo | ^nil' > shouldRaise: UnusedVariable; > compiling: 'griffle | | ^[ | goo | ]' > shouldRaise: UnusedVariable; > compiling: 'griffle | | [ | goo | goo := nil. goo] yourself. ^[ | goo | ]' > shouldRaise: UnusedVariable; > compiling: 'griffle | | [ | goo | ] yourself. ^[ | goo | goo := nil. goo]' > shouldRaise: UnusedVariable > > What happens is that Parser.scopeTable has a single entry for 'goo'. > Consequently, the last registered goo wins. > In the 3rd case, the last goo is unused, so hasRef = false, so > UnusedVariable is raised. > In the 4th case, the last goo nowHasRef, and we don't get any UnusedVariable. > > Until we get a scopeTable mapping each temp of each block, we gonna > live in trouble. > > Nicolas |
In reply to this post by Nicolas Cellier
On Thu, 13 Jan 2011, Nicolas Cellier wrote:
> Follow up on unused temps : > > Wanna play with temps ? Try this : > > testUnusedVariable > self > compiling: 'griffle | goo | ^nil' > shouldRaise: UnusedVariable; > compiling: 'griffle | | ^[ | goo | ]' > shouldRaise: UnusedVariable; > compiling: 'griffle | | [ | goo | goo := nil. goo] yourself. ^[ | goo | ]' > shouldRaise: UnusedVariable; > compiling: 'griffle | | [ | goo | ] yourself. ^[ | goo | goo := nil. goo]' > shouldRaise: UnusedVariable > > What happens is that Parser.scopeTable has a single entry for 'goo'. > Consequently, the last registered goo wins. > In the 3rd case, the last goo is unused, so hasRef = false, so > UnusedVariable is raised. > In the 4th case, the last goo nowHasRef, and we don't get any UnusedVariable. > > Until we get a scopeTable mapping each temp of each block, we gonna > live in trouble. because it's accessed in various ways from several places and it's hard to see what change will have side effects in the current code. But I'm a total newbie in this area, so I may be wrong. Levente > > Nicolas > > 2011/1/12 Nicolas Cellier <[hidden email]>: >> 2011/1/12 Levente Uzonyi <[hidden email]>: >>> On Wed, 12 Jan 2011, Chris Muller wrote: >>> >>>> I've just posted a new beta image at: >>>> >>>> ftp://ftp.squeak.org/4.2/ >>>> >>>> This one does not have wrecked PackageInfo's, and has most (but not >>>> all) of the aesthetic changes for 4.2. >>>> >>>> The test suite is looking better: >>>> >>>> 'CompilerExceptionsTest>>#testUnusedVariable >>> >>> This one is new, I'd be happy if someone could have a look at it. >>> >> >> This is due to latest improvements from Eliot. >> Now the BlockNode have their own tempsMark (set by >> Parser>>#temporaryBlockVariablesFor:). >> The Parser only records top level tempsMark in Parser>>#temporaries. >> >> If you look at the code in Parser>>#removeUnusedTemps, you see some >> defensive programming >> ((tempsMark between: 1 and: str size) >> and: [(str at: tempsMark) = $|]) ifFalse: [^ self]. >> >> But hey, the top level does not have any tempsMark, so the method >> prematurely returns without checking for some unused in the blocks. >> self >> justTriedCompiling: 'griffle | | ^[ | goo | ]' >> andItCorrectlyRaised: UnusedVariable. >> >> Shall we remove the tempsMark protection ? >> >> Nicolas >> > > |
2011/1/13 Levente Uzonyi <[hidden email]>
That's a good idea. One goal for anyone who tries to do anything in this area is to collapse optimized temps. e.g. in the following 1 to: self size do: [:i| ...].
1 to: self size do: [:j| ...] or 1 to: self size do: [:i| ...].1 to: self size do: [:i| ...]. the current scope table makes it really hard to use the same temp slot for either i and j or both i's. Since these temps are out of scope after their blocks their temps should be reused. But the compiler keeps the in-scope/out-of-scope info in the temp nodes themselves, so this can't be done.
Collapsing temps of different names is probably not feasible because there's no way to add teh necessary scope information to the debugger temp names string and so no way of saying "temp #T is called 'i' from bytecode M to bytecode N but is called 'j' from bytecode O to bytecode P". But collapsing temps with the same name is straight-forward and judging by all the code I've eyeballed in working on the closure compiler I'd say it was worth it, not least because certain large methods would limbo under the 56 slot max temp limit which wouldn't otherwise. remember that GeniePlugin method that couldn't be compiled until it was refactored.
2¢ Eliot Levente |
In reply to this post by Bert Freudenberg
On Thu, Jan 13, 2011 at 2:29 AM, Bert Freudenberg <[hidden email]> wrote: Here's another decompiler problem that I actually ran into in production code. When decompiling this method, either the block-local temp should remain block-local, or one of the vars needs to be renamed: Right. And there's now a visitor method for determining that scope, TempScopeEditor>>#blockNode:isEnclosingScopeFor:. But I've been too lazy^H^H^H^Hbusy to apply it in the context of the decompiler. Feel free to feel motivated...
best Eliot
|
On Thu, Jan 13, 2011 at 9:33 AM, Eliot Miranda <[hidden email]> wrote:
No, no, no, no, no, no, no. The visitor is VariableScopeFinder and the method is ofVariable: so aParseNode accept: (VariableScopeFinder new ofVariable: var) answers nil or the smallest enclosing scope for var in aParseNode. See Parser>>declareUndeclaredTemps.
|
In reply to this post by Eliot Miranda-2
On 13 January 2011 18:25, Eliot Miranda <[hidden email]> wrote:
> > I've eyeballed in working on the closure compiler I'd say it was worth it, > not least because certain large methods would limbo under the 56 slot max > temp limit which wouldn't otherwise. Well, if method contains so much temps, then probably a better workaround is to fix the programmer (or replace it, if it deeply broken), than modify compiler in order to deal with that. :) > 2¢ > Eliot >> >> Levente -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Chris Muller-3
On 01/12/2011 09:11 PM, Chris Muller wrote:
> SMDependencyTest>>#test2 Nuke that one, old stuff from when I was messing with deps I presume. regards, Göran |
In reply to this post by Eliot Miranda-2
Hi, We fiddled with this a bit.
The Decompiler modified by the attached changeset tries to do this. It gives the following output for your example: blockLocalsAndArgs
| product | product := 1. 1 to: 2
do: [:i | i = 1 ifTrue: [| factor | factor := 6.
product := product * factor] ifFalse: [#(9 ) do: [:factor | product := product * factor]]].
^ product = 54 But it brakes half of the DecompilerTests. Most of them because the Decompiler inserts nil assignments to the beginnings of some blocks. eg. [ | val | ... ] becomes [ | val | val := nil. .... ].
And there is this snippet of code: | aBlock | aBlock := Compiler evaluate: '| x y | [:a :b | x := a. y := b. x+y]'.
aBlock decompile which breaks an assertion in the Decompiler itself. So this is far from complete.
The changeset contains the following changes: - A new subclass of VariableScopeFinder: TempVariableScopeFinder. It finds scopes for tempvar nodes not just for undeclared nodes.
- In DecompilerConstructorForClosures>>#codeMethod:block:tempVars:primitive:class: instead of [ block temporaries: temporaries ], we execute [ temporaries := self pushDownTemps: temporaries toTheirInnermostPossibleScopesIn: block ]
- The method pushDownTemps:toTheirInnermostPossibleScopesIn: which tries to do what it's name suggests and returns with the temps remaining in the top level scope. Is this the right direction?
Cheers, Balázs pushDownTemps.st (4K) Download Attachment |
On Fri, Jan 14, 2011 at 2:42 PM, Balázs Kósi <[hidden email]> wrote:
> > Hi, > > We fiddled with this a bit. >> >> On Thu, Jan 13, 2011 at 6:52 PM, Eliot Miranda <[hidden email]> wrote: >>> >>> On Thu, Jan 13, 2011 at 9:33 AM, Eliot Miranda <[hidden email]> wrote: >>>> >>>> On Thu, Jan 13, 2011 at 2:29 AM, Bert Freudenberg <[hidden email]> wrote: >>>>> >>>>> Here's another decompiler problem that I actually ran into in production code. When decompiling this method, either the block-local temp should remain block-local, or one of the vars needs to be renamed: >>>>> >>>>> blockLocalsAndArgs >>>>> | product | >>>>> product := 1. >>>>> 1 to: 2 do: [:i | >>>>> i = 1 >>>>> ifTrue: [ | factor | factor := 6. >>>>> product := product * factor ] >>>>> ifFalse: [ #(9) do: [:factor | >>>>> product := product * factor ] ] ]. >>>>> ^ product = 13r42 >>>>> >>>>> This works fine if decompiled without temps but the standard in Squeak is to use the actual temp names - just accept this as a method and switch to decompiled view. >>>>> >>>>> The best fix might be if the decompiler always declared the variables in the inner-most block possible. Maybe moving the declarations is not even that hard to do as a post-process on the AST > > The Decompiler modified by the attached changeset tries to do this. It gives the following output for your example: > blockLocalsAndArgs > | product | > product := 1. > 1 > to: 2 > do: [:i | i = 1 > ifTrue: [| factor | > factor := 6. > product := product * factor] > ifFalse: [#(9 ) > do: [:factor | product := product * factor]]]. > ^ product = 54 > > But it brakes half of the DecompilerTests. Most of them because the Decompiler inserts nil assignments to the beginnings of some blocks. eg. [ | val | ... ] becomes [ | val | val := nil. .... ]. > > And there is this snippet of code: > > | aBlock | > aBlock := Compiler evaluate: '| x y | [:a :b | x := a. y := b. x+y]'. > aBlock decompile > > which breaks an assertion in the Decompiler itself. > > So this is far from complete. >> >> >>>> >>>> Right. And there's now a visitor method for determining that scope, TempScopeEditor>>#blockNode:isEnclosingScopeFor:. But I've been too lazy^H^H^H^Hbusy to apply it in the context of the decompiler. Feel free to feel motivated... >>> >>> No, no, no, no, no, no, no. The visitor is VariableScopeFinder and the method is ofVariable: so aParseNode accept: (VariableScopeFinder new ofVariable: var) answers nil or the smallest enclosing scope for var in aParseNode. See Parser>>declareUndeclaredTemps. > > > The changeset contains the following changes: > - A new subclass of VariableScopeFinder: TempVariableScopeFinder. It finds scopes for tempvar nodes not just for undeclared nodes. > - In DecompilerConstructorForClosures>>#codeMethod:block:tempVars:primitive:class: instead of > [ block temporaries: temporaries ], we execute > [ temporaries := self pushDownTemps: temporaries toTheirInnermostPossibleScopesIn: block ] > - The method pushDownTemps:toTheirInnermostPossibleScopesIn: which tries to do what it's name suggests and returns with the temps remaining in the top level scope. > > Is this the right direction? > > Cheers, Balázs http://lists.squeakfoundation.org/pipermail/squeak-dev/2011-January/156794.html says "Skipped content of type multipart/alternative" pushDownTemps.st (4K) Download Attachment |
In reply to this post by Balázs Kósi
On Fri, Jan 14, 2011 at 5:42 AM, Balázs Kósi <[hidden email]> wrote:
It should only do this for inlined blocks that are in loops (to:do:, to:by:do: whileTrue: whileTrue whileFalse whileFalse:). I would modify the decompiler to strip the val := nil, since it is implicit; all temps are implicitly initialized to nil on entry to their scope. The compiler inserts the val := nil assignments to achieve this for blocks inlined in loops. If it didn't a subsequent enumeration of the block could see the value of a local from a previous iteration.
e.g. 1 to: 10 do: [:i| | local | self assert: local isNil. local := i] There is a test for this in the Compiler tests somewhere.
Yes!
thank you! best Eliot |
Free forum by Nabble | Edit this page |