I did a minor class-hierarchy refactoring today which resulted in a an
invalid super pointer, resulting in a confusing image lock up due to tight recursion. The script, below, demonstrates the issue in trunk: Object compile: 'test ^''Hello from Object'''. (Object subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test') compile: 'test ^ super halt test, ''my super call lands on myself!'''. (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test'). (Smalltalk classNamed: #MyNewAbstraction) new test But an existing method in the original MyClass had a call to super which now lands in itself, resulting in a tight recursion. The same script without creating the new subclass results in an instant VM crash (both interpreter 2357 and cog 3205): Object compile: 'test ^''Hello from Object'''. (Object subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test') compile: 'test ^ super halt test, ''my super call lands on itself!'''. (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. (Smalltalk classNamed: #MyNewAbstraction) new test I even tried recompiling my entire class hierarchy which was renamed, but it didn't help. How can this be? I _KNOW_ I've used rename class many times in the past... A regression? I went all the way back to 4.2. The above script doesn't crash the VM in 4.2 or 4.3. Squeak 4.4 and 4.5 and trunk all crash by the above script. All of those images (4.2 -- trunk) had the problem with the super pointer back to itself.. |
Hi,
On 15.01.2015, at 23:48, Chris Muller <[hidden email]> wrote: > I did a minor class-hierarchy refactoring today which resulted in a an > invalid super pointer, resulting in a confusing image lock up due to > tight recursion. The script, below, demonstrates the issue in trunk: > > Object compile: 'test ^''Hello from Object'''. > (Object subclass: #MyClass instanceVariableNames: '' > classVariableNames: '' poolDictionaries: '' category: 'Test') compile: > 'test ^ super halt test, ''my super call lands on myself!'''. > (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. > ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass > instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' > category: 'Test'). > (Smalltalk classNamed: #MyNewAbstraction) new test > > But an existing method in the original MyClass had a call to super > which now lands in itself, resulting in a tight recursion. > > The same script without creating the new subclass results in an > instant VM crash (both interpreter 2357 and cog 3205): > > Object compile: 'test ^''Hello from Object'''. > (Object subclass: #MyClass instanceVariableNames: '' > classVariableNames: '' poolDictionaries: '' category: 'Test') compile: > 'test ^ super halt test, ''my super call lands on itself!'''. > (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. > (Smalltalk classNamed: #MyNewAbstraction) new test > > I even tried recompiling my entire class hierarchy which was renamed, > but it didn't help. > > How can this be? I _KNOW_ I've used rename class many times in the > past... A regression? > > I went all the way back to 4.2. The above script doesn't crash the VM > in 4.2 or 4.3. Squeak 4.4 and 4.5 and trunk all crash by the above > script. > > All of those images (4.2 -- trunk) had the problem with the super > pointer back to itself.. I experienced this very problem in these minutes also. Best -Tobias |
I'm starting to suspect Environments. The last-literal binding is not
updated after rename.. Object compile: 'test ^''Hello from Object'''. (Object subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test') compile: 'test ^ super halt test, ''my super call lands on itself!'''. ((Smalltalk classNamed: #MyClass) methodDictionary at: #test) explore. self halt: 'About to rename'. (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. ((Smalltalk classNamed: #MyNewAbstraction) methodDictionary at: #test) explore. self halt: 'About to add MyClass as subclass'. ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test'). (Smalltalk classNamed: #MyNewAbstraction) new test On Thu, Jan 15, 2015 at 5:11 PM, Tobias Pape <[hidden email]> wrote: > Hi, > > On 15.01.2015, at 23:48, Chris Muller <[hidden email]> wrote: > >> I did a minor class-hierarchy refactoring today which resulted in a an >> invalid super pointer, resulting in a confusing image lock up due to >> tight recursion. The script, below, demonstrates the issue in trunk: >> >> Object compile: 'test ^''Hello from Object'''. >> (Object subclass: #MyClass instanceVariableNames: '' >> classVariableNames: '' poolDictionaries: '' category: 'Test') compile: >> 'test ^ super halt test, ''my super call lands on myself!'''. >> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass >> instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' >> category: 'Test'). >> (Smalltalk classNamed: #MyNewAbstraction) new test >> >> But an existing method in the original MyClass had a call to super >> which now lands in itself, resulting in a tight recursion. >> >> The same script without creating the new subclass results in an >> instant VM crash (both interpreter 2357 and cog 3205): >> >> Object compile: 'test ^''Hello from Object'''. >> (Object subclass: #MyClass instanceVariableNames: '' >> classVariableNames: '' poolDictionaries: '' category: 'Test') compile: >> 'test ^ super halt test, ''my super call lands on itself!'''. >> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> (Smalltalk classNamed: #MyNewAbstraction) new test >> >> I even tried recompiling my entire class hierarchy which was renamed, >> but it didn't help. >> >> How can this be? I _KNOW_ I've used rename class many times in the >> past... A regression? >> >> I went all the way back to 4.2. The above script doesn't crash the VM >> in 4.2 or 4.3. Squeak 4.4 and 4.5 and trunk all crash by the above >> script. >> >> All of those images (4.2 -- trunk) had the problem with the super >> pointer back to itself.. > > I experienced this very problem in these minutes also. > > Best > -Tobias > > > |
In reply to this post by Chris Muller-4
Hi Chris, Hi Colin,
On Thu, Jan 15, 2015 at 2:48 PM, Chris Muller <[hidden email]> wrote: I did a minor class-hierarchy refactoring today which resulted in a an This is indeed an Environments regression. The issue is where to fix the problem. One way to look at it is that Environment>>renameClass:from:to: does not update bindings in the renamed class's methods. Here's what the old code did: SystemDictionary>>renameClass: aClass from: oldName to: newName "Rename the class, aClass, to have the title newName." | oldref category | category := SystemOrganization categoryOfElement: oldName. self organization classify: newName under: category suppressIfDefault: true. self organization removeElement: oldName. oldref := self associationAt: oldName. self removeKey: oldName. ** oldref key: newName. self add: oldref. "Old association preserves old refs" Smalltalk renamedClass: aClass from: oldName to: newName. self flushClassNameCache. SystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName to: newName inCategory: category The starred line changes the key on the old class's binding, meaning that all the methods whose methodClassAssociation is that binding get automatically updated (note that class methods have a methodClassAssociation that has no key and just points to the class object). The new code simply forgets to do this: Environment>>renameClass: aClass from: oldName to: newName "Rename the class, aClass, to have the title newName." | binding category | category := self organization categoryOfElement: oldName. self organization classify: newName under: category suppressIfDefault: true. self organization removeElement: oldName. binding := self declarationOf: oldName. declarations removeKey: oldName. self binding: binding removedFrom: self. binding := newName => aClass. declarations add: binding. self binding: binding addedTo: self. Smalltalk renamedClass: aClass from: oldName to: newName. SystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName to: newName inCategory: category But should the change go in Environment>>renameClass:from:to: or in the BindingPolicy? i.e. it could be implemented either in Environment>>renameClass:from:to:, or in Environment>>showBinding:. I guess the former, but I'm cc'ing Colin, because know it?, he wrote it! In any case there needs to be a test that checks that a method's methodClassAssociation is correctly updated after a rename. I bet Colin would have not made this slip had there been a test. Here's the code I used to test this: | mca1 mca2 | Object compile: 'test ^''Hello from Object'''. (Object subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test') compile: 'test ^ super halt test, ''my super call lands on itself!'''. mca1 := ((Smalltalk classNamed: #MyClass)>>#test) methodClassAssociation. (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. mca2 := ((Smalltalk classNamed: #MyNewAbstraction)>>#test) methodClassAssociation. { mca1. mca2. mca1 == mca2. mca1 == (Smalltalk bindingOf: #MyNewAbstraction). mca2 == (Smalltalk bindingOf: #MyNewAbstraction)} It answers { #MyClass=>nil . #MyClass=>nil . true . false . false} i.e. the binding isn't updated, but changes from #MyClass=>MyClass to #MyClass=>nil in binding:removedFrom:. HTH,
Eliot |
On Tue, Jan 20, 2015 at 12:26 PM, Eliot Miranda <[hidden email]> wrote:
and if the fix should indeed go in Environment>>renameClass:from:to: , it is as simple as Environment>>renameClass: aClass from: oldName to: newName "Rename the class, aClass, to have the title newName." | binding category | category := self organization categoryOfElement: oldName. self organization classify: newName under: category suppressIfDefault: true. self organization removeElement: oldName. binding := self declarationOf: oldName. declarations removeKey: oldName. self binding: binding removedFrom: self. binding := newName => aClass. declarations add: binding. self binding: binding addedTo: self. ** aClass updateMethodBindingsTo: binding. Smalltalk renamedClass: aClass from: oldName to: newName. SystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName to: newName inCategory: category I'll make this change and we can alter later if Colin thinks it's in the wrong place.
best,
Eliot |
On 20.01.2015, at 21:33, Eliot Miranda <[hidden email]> wrote: > On Tue, Jan 20, 2015 at 12:26 PM, Eliot Miranda <[hidden email]> wrote: > Hi Chris, Hi Colin, > > > On Thu, Jan 15, 2015 at 2:48 PM, Chris Muller <[hidden email]> wrote: > I did a minor class-hierarchy refactoring today which resulted in a an > invalid super pointer, resulting in a confusing image lock up due to > tight recursion. The script, below, demonstrates the issue in trunk: > > Object compile: 'test ^''Hello from Object'''. > (Object subclass: #MyClass instanceVariableNames: '' > classVariableNames: '' poolDictionaries: '' category: 'Test') compile: > 'test ^ super halt test, ''my super call lands on myself!'''. > (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. > ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass > instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' > category: 'Test'). > (Smalltalk classNamed: #MyNewAbstraction) new test > > But an existing method in the original MyClass had a call to super > which now lands in itself, resulting in a tight recursion. > > The same script without creating the new subclass results in an > instant VM crash (both interpreter 2357 and cog 3205): > > Object compile: 'test ^''Hello from Object'''. > (Object subclass: #MyClass instanceVariableNames: '' > classVariableNames: '' poolDictionaries: '' category: 'Test') compile: > 'test ^ super halt test, ''my super call lands on itself!'''. > (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. > (Smalltalk classNamed: #MyNewAbstraction) new test > > I even tried recompiling my entire class hierarchy which was renamed, > but it didn't help. > > How can this be? I _KNOW_ I've used rename class many times in the > past... A regression? > > This is indeed an Environments regression. The issue is where to fix the problem. One way to look at it is that Environment>>renameClass:from:to: does not update bindings in the renamed class's methods. > > Here's what the old code did: > > SystemDictionary>>renameClass: aClass from: oldName to: newName > "Rename the class, aClass, to have the title newName." > > | oldref category | > category := SystemOrganization categoryOfElement: oldName. > self organization classify: newName under: category suppressIfDefault: true. > self organization removeElement: oldName. > oldref := self associationAt: oldName. > self removeKey: oldName. > ** oldref key: newName. > self add: oldref. "Old association preserves old refs" > Smalltalk renamedClass: aClass from: oldName to: newName. > self flushClassNameCache. > SystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName to: newName inCategory: category > > The starred line changes the key on the old class's binding, meaning that all the methods whose methodClassAssociation is that binding get automatically updated (note that class methods have a methodClassAssociation that has no key and just points to the class object). > > The new code simply forgets to do this: > > Environment>>renameClass: aClass from: oldName to: newName > "Rename the class, aClass, to have the title newName." > > | binding category | > category := self organization categoryOfElement: oldName. > self organization classify: newName under: category suppressIfDefault: true. > self organization removeElement: oldName. > > binding := self declarationOf: oldName. > declarations removeKey: oldName. > self binding: binding removedFrom: self. > > binding := newName => aClass. > declarations add: binding. > self binding: binding addedTo: self. > > Smalltalk renamedClass: aClass from: oldName to: newName. > SystemChangeNotifier uniqueInstance > classRenamed: aClass > from: oldName > to: newName > inCategory: category > > > But should the change go in Environment>>renameClass:from:to: or in the BindingPolicy? i.e. it could be implemented either in Environment>>renameClass:from:to:, or in Environment>>showBinding:. I guess the former, but I'm cc'ing Colin, because know it?, he wrote it! > > and if the fix should indeed go in Environment>>renameClass:from:to: , it is as simple as > > Environment>>renameClass: aClass from: oldName to: newName > "Rename the class, aClass, to have the title newName." > > | binding category | > category := self organization categoryOfElement: oldName. > self organization classify: newName under: category suppressIfDefault: true. > self organization removeElement: oldName. > > binding := self declarationOf: oldName. > declarations removeKey: oldName. > self binding: binding removedFrom: self. > > binding := newName => aClass. > declarations add: binding. > self binding: binding addedTo: self. > > ** aClass updateMethodBindingsTo: binding. > > Smalltalk renamedClass: aClass from: oldName to: newName. > SystemChangeNotifier uniqueInstance > classRenamed: aClass > from: oldName > to: newName > inCategory: category > > I'll make this change and we can alter later if Colin thinks it's in the wrong place. > > Eliot, be sure to check my changes before you do that. We try to fix the same problem! Best -Tobias > In any case there needs to be a test that checks that a method's methodClassAssociation is correctly updated after a rename. I bet Colin would have not made this slip had there been a test. > > > Here's the code I used to test this: > > | mca1 mca2 | > Object compile: 'test ^''Hello from Object'''. > (Object > subclass: #MyClass instanceVariableNames: '' > classVariableNames: '' > poolDictionaries: '' > category: 'Test') > compile: 'test ^ super halt test, ''my super call lands on itself!'''. > mca1 := ((Smalltalk classNamed: #MyClass)>>#test) methodClassAssociation. > (Smalltalk classNamed: #MyClass) > rename: 'MyNewAbstraction'. > mca2 := ((Smalltalk classNamed: #MyNewAbstraction)>>#test) methodClassAssociation. > { mca1. mca2. mca1 == mca2. mca1 == (Smalltalk bindingOf: #MyNewAbstraction). mca2 == (Smalltalk bindingOf: #MyNewAbstraction)} > > It answers { #MyClass=>nil . #MyClass=>nil . true . false . false} > i.e. the binding isn't updated, but changes from #MyClass=>MyClass to #MyClass=>nil in binding:removedFrom:. |
In reply to this post by Eliot Miranda-2
Ugh, I'm behind the times, Tobias you've already fixed it; thanks! Tobias, I like your use of becomeForward:; it is more robust. But I *think* the undeclared removal is misplaced. Don't you think that that code belongs in the BindingPolicy? On Tue, Jan 20, 2015 at 12:33 PM, Eliot Miranda <[hidden email]> wrote:
best,
Eliot |
On 20.01.2015, at 21:38, Eliot Miranda <[hidden email]> wrote: > Ugh, I'm behind the times, Tobias you've already fixed it; thanks! Tobias, I like your use of becomeForward:; it is more robust. But I *think* the undeclared removal is misplaced. Don't you think that that code belongs in the BindingPolicy? Probably this is true, but then BindingPolicy has to have a notion of renaming, which it does not have to this point. The removal from the undeclared is only sensible in the renaming case. Best -Tobias PS: Other comments in the other mail. |
In reply to this post by Eliot Miranda-2
Hi,
On 20.01.2015, at 21:33, Eliot Miranda <[hidden email]> wrote: > > ** aClass updateMethodBindingsTo: binding. While this will fix the home method problem, the effect is that other bindings are not updated. Probabl A) In 4.4, this works: | p | p := Object subclass: #Peter instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Unknown'. p compile: 'susi ^ Peter new'. " literals of #susi: {#Peter->Peter . #susi . #Peter->Peter} " p rename: #Anton. " literals of #susi: {#Anton->Anton . #susi . #Anton->Anton} " p new susi. "Works, returns an Anton, but source is out of sync" B) In 4.5: | p | p := Object subclass: #Peter instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Unknown'. p compile: 'susi ^ Peter new'. " literals of #susi: {#Peter=>Peter . #susi . #Peter=>Peter} " p rename: #Anton. " literals of #susi: {#Peter=>nil . #susi . #Peter=>nil} " p new susi. "Does not work, throws a DNU on nil, using #susi may crash the vm " C) In Trunk, after Environments-topa.54: | p | p := Object subclass: #Peter instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Unknown'. p compile: 'susi ^ Peter new'. " literals of #susi: {#Peter=>Peter . #susi . #Peter=>Peter} " p rename: #Anton. " literals of #susi: {#Anton=>Anton . #susi . #Anton=>Anton} " p new susi. "Works, returns an Anton, but source is out of sync" So, we got the 4.4 behavior back. However, Colin (cc) explicitly has a test that checks that a rename actually creates a new binding[1]. This mean, with Eliot's patch it would look like this: D) | p | p := Object subclass: #Peter instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Unknown'. p compile: 'susi ^ Peter new'. " literals of #susi: {#Peter=>Peter . #susi . #Peter=>Peter} " p rename: #Anton. " literals of #susi: {#Peter=>nil . #susi . #Anton=>Anton} " p new susi. "Does not work, throws a DNU on nil, would not crash the VM, Source is in sync, because Peter is now undeclared." After some discussion with Bert, we came to the conclusion that either of C) or D) can be desirable; the literal `Peter` is actually undeclared (as per D)) and probably running into an error is the right thing. Yet C) retains backwards compatibility. Ideas? Best -Tobias [1]: Colin, could you elaborate on that? |
In reply to this post by Eliot Miranda-2
(got interrupted writing this, and now the discussion has progressed, but I'll send anyway)
On 20.01.2015, at 21:26, Eliot Miranda <[hidden email]> wrote: > > This is indeed an Environments regression. The issue is where to fix the problem. One way to look at it is that Environment>>renameClass:from:to: does not update bindings in the renamed class's methods. I sat down with Tobias today, and a fix is in Trunk. It updates the bindings in method literals. > I bet Colin would have not made this slip had there been a test. It seemed to me as if Colin made a conscious decision to not keep the binding "alive". Instead, he changed the bindings in the compiled method to be #OldName->nil and puts it in Undeclared, and created a new binding in the environment as #NewName->aClass. There is even a test ensuring that oldBinding ~~ newBinding. I guess this is to ensure that what the method source says matches what the compiled method does. After renaming the class, the source code still uses OldName, but accepting it as-is would result in a binding like #OldName->nil to be created in Undeclared. Essentially, this way of doing it ensures that decompiling the method is not different from the actual source after a class rename, both use 'OldName'. However, I'd argue it's more important that the system keeps working while renaming a class. That's what the old scheme did - it simply stored the new class name as key of the binding, not disturbing execution at all. Our fix restores that behavior, albeit using #becomeForward: as did Colin's code, and we were not exactly sure, why. I still don't see why the become would be necessary. Note that we did not actually test this with multiple environments, aliases etc. One idea I had after this is that we perhaps could move the old binding to undeclared (keeping methods both working and decompilable) and additionally create a new binding under the new class name. Perhaps this is what Colin intended all along, and it was only the implementation that was buggy? If we knew exactly what we want, it seems like the environment code is reasonably simple to make it do that. - Bert - smime.p7s (5K) Download Attachment |
In reply to this post by Eliot Miranda-2
Hi Eliot, there were TWO problems, Bert and Tobias have fixed one of
them. The second one is still unfixed in trunk. When you run this script and arrive at the debugger, step INTO: Object compile: 'test ^''Hello from Object'''. (Object subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test') compile: 'test ^ super halt test, ''my super call lands on itself!'''. (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. (Smalltalk classNamed: #MyNewAbstraction) new test then be sure to step INTO the super call to #test. See how it lands you in teh same method? THAT bug exists back at least as far back as 4.2, so I don't think its Environments related. I took a look at it and presented my findings in the other email thread with subject "The Inbox: Environments-cmm.52.mcz", -- that screenshot showing that the bytecodes are teh same and the literal binding looks correct. So I have no idea why its not calling super correctly... On Tue, Jan 20, 2015 at 2:38 PM, Eliot Miranda <[hidden email]> wrote: > > Ugh, I'm behind the times, Tobias you've already fixed it; thanks! Tobias, I like your use of becomeForward:; it is more robust. But I *think* the undeclared removal is misplaced. Don't you think that that code belongs in the BindingPolicy? > > On Tue, Jan 20, 2015 at 12:33 PM, Eliot Miranda <[hidden email]> wrote: >> >> >> >> On Tue, Jan 20, 2015 at 12:26 PM, Eliot Miranda <[hidden email]> wrote: >>> >>> Hi Chris, Hi Colin, >>> >>> >>> On Thu, Jan 15, 2015 at 2:48 PM, Chris Muller <[hidden email]> wrote: >>>> >>>> I did a minor class-hierarchy refactoring today which resulted in a an >>>> invalid super pointer, resulting in a confusing image lock up due to >>>> tight recursion. The script, below, demonstrates the issue in trunk: >>>> >>>> Object compile: 'test ^''Hello from Object'''. >>>> (Object subclass: #MyClass instanceVariableNames: '' >>>> classVariableNames: '' poolDictionaries: '' category: 'Test') compile: >>>> 'test ^ super halt test, ''my super call lands on myself!'''. >>>> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >>>> ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass >>>> instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' >>>> category: 'Test'). >>>> (Smalltalk classNamed: #MyNewAbstraction) new test >>>> >>>> But an existing method in the original MyClass had a call to super >>>> which now lands in itself, resulting in a tight recursion. >>>> >>>> The same script without creating the new subclass results in an >>>> instant VM crash (both interpreter 2357 and cog 3205): >>>> >>>> Object compile: 'test ^''Hello from Object'''. >>>> (Object subclass: #MyClass instanceVariableNames: '' >>>> classVariableNames: '' poolDictionaries: '' category: 'Test') compile: >>>> 'test ^ super halt test, ''my super call lands on itself!'''. >>>> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >>>> (Smalltalk classNamed: #MyNewAbstraction) new test >>>> >>>> I even tried recompiling my entire class hierarchy which was renamed, >>>> but it didn't help. >>>> >>>> How can this be? I _KNOW_ I've used rename class many times in the >>>> past... A regression? >>> >>> >>> This is indeed an Environments regression. The issue is where to fix the problem. One way to look at it is that Environment>>renameClass:from:to: does not update bindings in the renamed class's methods. >>> >>> Here's what the old code did: >>> >>> SystemDictionary>>renameClass: aClass from: oldName to: newName >>> "Rename the class, aClass, to have the title newName." >>> >>> | oldref category | >>> category := SystemOrganization categoryOfElement: oldName. >>> self organization classify: newName under: category suppressIfDefault: true. >>> self organization removeElement: oldName. >>> oldref := self associationAt: oldName. >>> self removeKey: oldName. >>> ** oldref key: newName. >>> self add: oldref. "Old association preserves old refs" >>> Smalltalk renamedClass: aClass from: oldName to: newName. >>> self flushClassNameCache. >>> SystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName to: newName inCategory: category >>> >>> The starred line changes the key on the old class's binding, meaning that all the methods whose methodClassAssociation is that binding get automatically updated (note that class methods have a methodClassAssociation that has no key and just points to the class object). >>> >>> The new code simply forgets to do this: >>> >>> Environment>>renameClass: aClass from: oldName to: newName >>> "Rename the class, aClass, to have the title newName." >>> >>> | binding category | >>> category := self organization categoryOfElement: oldName. >>> self organization classify: newName under: category suppressIfDefault: true. >>> self organization removeElement: oldName. >>> binding := self declarationOf: oldName. >>> declarations removeKey: oldName. >>> self binding: binding removedFrom: self. >>> binding := newName => aClass. >>> declarations add: binding. >>> self binding: binding addedTo: self. >>> Smalltalk renamedClass: aClass from: oldName to: newName. >>> SystemChangeNotifier uniqueInstance >>> classRenamed: aClass >>> from: oldName >>> to: newName >>> inCategory: category >>> >>> >>> But should the change go in Environment>>renameClass:from:to: or in the BindingPolicy? i.e. it could be implemented either in Environment>>renameClass:from:to:, or in Environment>>showBinding:. I guess the former, but I'm cc'ing Colin, because know it?, he wrote it! >> >> >> and if the fix should indeed go in Environment>>renameClass:from:to: , it is as simple as >> >> Environment>>renameClass: aClass from: oldName to: newName >> "Rename the class, aClass, to have the title newName." >> >> | binding category | >> category := self organization categoryOfElement: oldName. >> self organization classify: newName under: category suppressIfDefault: true. >> self organization removeElement: oldName. >> binding := self declarationOf: oldName. >> declarations removeKey: oldName. >> self binding: binding removedFrom: self. >> binding := newName => aClass. >> declarations add: binding. >> self binding: binding addedTo: self. >> >> ** aClass updateMethodBindingsTo: binding. >> Smalltalk renamedClass: aClass from: oldName to: newName. >> SystemChangeNotifier uniqueInstance >> classRenamed: aClass >> from: oldName >> to: newName >> inCategory: category >> >> I'll make this change and we can alter later if Colin thinks it's in the wrong place. >> >>> >>> >>> In any case there needs to be a test that checks that a method's methodClassAssociation is correctly updated after a rename. I bet Colin would have not made this slip had there been a test. >>> >>> >>> Here's the code I used to test this: >>> >>> | mca1 mca2 | >>> Object compile: 'test ^''Hello from Object'''. >>> (Object >>> subclass: #MyClass instanceVariableNames: '' >>> classVariableNames: '' >>> poolDictionaries: '' >>> category: 'Test') >>> compile: 'test ^ super halt test, ''my super call lands on itself!'''. >>> mca1 := ((Smalltalk classNamed: #MyClass)>>#test) methodClassAssociation. >>> (Smalltalk classNamed: #MyClass) >>> rename: 'MyNewAbstraction'. >>> mca2 := ((Smalltalk classNamed: #MyNewAbstraction)>>#test) methodClassAssociation. >>> { mca1. mca2. mca1 == mca2. mca1 == (Smalltalk bindingOf: #MyNewAbstraction). mca2 == (Smalltalk bindingOf: #MyNewAbstraction)} >>> >>> It answers { #MyClass=>nil . #MyClass=>nil . true . false . false} >>> i.e. the binding isn't updated, but changes from #MyClass=>MyClass to #MyClass=>nil in binding:removedFrom:. >>> >>> >>> -- >>> HTH, >>> Eliot >> >> >> >> >> -- >> best, >> Eliot > > > > > -- > best, > Eliot > > > |
2015-01-20 23:56 GMT+01:00 Chris Muller <[hidden email]>: Hi Eliot, there were TWO problems, Bert and Tobias have fixed one of But it behaves as it should... You first send halt to super. If you resume it just answer self. Then you send test to self (it's not a super send and never been) then be sure to step INTO the super call to #test. See how it lands |
OMG.... :$ LOL!! I'm sooo embarassed..!
I never write "super someMethodOtherThanTheOneImIn" but I sure did that with "super halt" didn't I? Duh. Now I'm wondering what my recursion was that locked up because it didn't have a halt in the loop.. Ugg, sorry, if I find this bug again I'll take better care to recreate it. :) On Tue, Jan 20, 2015 at 6:05 PM, Nicolas Cellier <[hidden email]> wrote: > > > 2015-01-20 23:56 GMT+01:00 Chris Muller <[hidden email]>: >> >> Hi Eliot, there were TWO problems, Bert and Tobias have fixed one of >> them. The second one is still unfixed in trunk. When you run this >> script and arrive at the debugger, step INTO: >> >> Object compile: 'test ^''Hello from Object'''. >> (Object subclass: #MyClass instanceVariableNames: '' >> classVariableNames: '' poolDictionaries: '' category: 'Test') compile: >> 'test ^ super halt test, ''my super call lands on itself!'''. >> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> (Smalltalk classNamed: #MyNewAbstraction) new test >> > > But it behaves as it should... > You first send halt to super. > If you resume it just answer self. > > Then you send test to self (it's not a super send and never been) > > >> >> then be sure to step INTO the super call to #test. See how it lands >> you in teh same method? THAT bug exists back at least as far back as >> 4.2, so I don't think its Environments related. >> >> I took a look at it and presented my findings in the other email >> thread with subject "The Inbox: Environments-cmm.52.mcz", -- that >> screenshot showing that the bytecodes are teh same and the literal >> binding looks correct. >> >> So I have no idea why its not calling super correctly... >> >> >> On Tue, Jan 20, 2015 at 2:38 PM, Eliot Miranda <[hidden email]> >> wrote: >> > >> > Ugh, I'm behind the times, Tobias you've already fixed it; thanks! >> > Tobias, I like your use of becomeForward:; it is more robust. But I *think* >> > the undeclared removal is misplaced. Don't you think that that code belongs >> > in the BindingPolicy? >> > >> > On Tue, Jan 20, 2015 at 12:33 PM, Eliot Miranda >> > <[hidden email]> wrote: >> >> >> >> >> >> >> >> On Tue, Jan 20, 2015 at 12:26 PM, Eliot Miranda >> >> <[hidden email]> wrote: >> >>> >> >>> Hi Chris, Hi Colin, >> >>> >> >>> >> >>> On Thu, Jan 15, 2015 at 2:48 PM, Chris Muller <[hidden email]> >> >>> wrote: >> >>>> >> >>>> I did a minor class-hierarchy refactoring today which resulted in a >> >>>> an >> >>>> invalid super pointer, resulting in a confusing image lock up due to >> >>>> tight recursion. The script, below, demonstrates the issue in trunk: >> >>>> >> >>>> Object compile: 'test ^''Hello from Object'''. >> >>>> (Object subclass: #MyClass instanceVariableNames: '' >> >>>> classVariableNames: '' poolDictionaries: '' category: 'Test') >> >>>> compile: >> >>>> 'test ^ super halt test, ''my super call lands on myself!'''. >> >>>> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> >>>> ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass >> >>>> instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' >> >>>> category: 'Test'). >> >>>> (Smalltalk classNamed: #MyNewAbstraction) new test >> >>>> >> >>>> But an existing method in the original MyClass had a call to super >> >>>> which now lands in itself, resulting in a tight recursion. >> >>>> >> >>>> The same script without creating the new subclass results in an >> >>>> instant VM crash (both interpreter 2357 and cog 3205): >> >>>> >> >>>> Object compile: 'test ^''Hello from Object'''. >> >>>> (Object subclass: #MyClass instanceVariableNames: '' >> >>>> classVariableNames: '' poolDictionaries: '' category: 'Test') >> >>>> compile: >> >>>> 'test ^ super halt test, ''my super call lands on itself!'''. >> >>>> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> >>>> (Smalltalk classNamed: #MyNewAbstraction) new test >> >>>> >> >>>> I even tried recompiling my entire class hierarchy which was renamed, >> >>>> but it didn't help. >> >>>> >> >>>> How can this be? I _KNOW_ I've used rename class many times in the >> >>>> past... A regression? >> >>> >> >>> >> >>> This is indeed an Environments regression. The issue is where to fix >> >>> the problem. One way to look at it is that >> >>> Environment>>renameClass:from:to: does not update bindings in the renamed >> >>> class's methods. >> >>> >> >>> Here's what the old code did: >> >>> >> >>> SystemDictionary>>renameClass: aClass from: oldName to: newName >> >>> "Rename the class, aClass, to have the title newName." >> >>> >> >>> | oldref category | >> >>> category := SystemOrganization categoryOfElement: oldName. >> >>> self organization classify: newName under: category suppressIfDefault: >> >>> true. >> >>> self organization removeElement: oldName. >> >>> oldref := self associationAt: oldName. >> >>> self removeKey: oldName. >> >>> ** oldref key: newName. >> >>> self add: oldref. "Old association preserves old refs" >> >>> Smalltalk renamedClass: aClass from: oldName to: newName. >> >>> self flushClassNameCache. >> >>> SystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName >> >>> to: newName inCategory: category >> >>> >> >>> The starred line changes the key on the old class's binding, meaning >> >>> that all the methods whose methodClassAssociation is that binding get >> >>> automatically updated (note that class methods have a methodClassAssociation >> >>> that has no key and just points to the class object). >> >>> >> >>> The new code simply forgets to do this: >> >>> >> >>> Environment>>renameClass: aClass from: oldName to: newName >> >>> "Rename the class, aClass, to have the title newName." >> >>> >> >>> | binding category | >> >>> category := self organization categoryOfElement: oldName. >> >>> self organization classify: newName under: category suppressIfDefault: >> >>> true. >> >>> self organization removeElement: oldName. >> >>> binding := self declarationOf: oldName. >> >>> declarations removeKey: oldName. >> >>> self binding: binding removedFrom: self. >> >>> binding := newName => aClass. >> >>> declarations add: binding. >> >>> self binding: binding addedTo: self. >> >>> Smalltalk renamedClass: aClass from: oldName to: newName. >> >>> SystemChangeNotifier uniqueInstance >> >>> classRenamed: aClass >> >>> from: oldName >> >>> to: newName >> >>> inCategory: category >> >>> >> >>> >> >>> But should the change go in Environment>>renameClass:from:to: or in >> >>> the BindingPolicy? i.e. it could be implemented either in >> >>> Environment>>renameClass:from:to:, or in Environment>>showBinding:. I guess >> >>> the former, but I'm cc'ing Colin, because know it?, he wrote it! >> >> >> >> >> >> and if the fix should indeed go in Environment>>renameClass:from:to: , >> >> it is as simple as >> >> >> >> Environment>>renameClass: aClass from: oldName to: newName >> >> "Rename the class, aClass, to have the title newName." >> >> >> >> | binding category | >> >> category := self organization categoryOfElement: oldName. >> >> self organization classify: newName under: category suppressIfDefault: >> >> true. >> >> self organization removeElement: oldName. >> >> binding := self declarationOf: oldName. >> >> declarations removeKey: oldName. >> >> self binding: binding removedFrom: self. >> >> binding := newName => aClass. >> >> declarations add: binding. >> >> self binding: binding addedTo: self. >> >> >> >> ** aClass updateMethodBindingsTo: binding. >> >> Smalltalk renamedClass: aClass from: oldName to: newName. >> >> SystemChangeNotifier uniqueInstance >> >> classRenamed: aClass >> >> from: oldName >> >> to: newName >> >> inCategory: category >> >> >> >> I'll make this change and we can alter later if Colin thinks it's in >> >> the wrong place. >> >> >> >>> >> >>> >> >>> In any case there needs to be a test that checks that a method's >> >>> methodClassAssociation is correctly updated after a rename. I bet Colin >> >>> would have not made this slip had there been a test. >> >>> >> >>> >> >>> Here's the code I used to test this: >> >>> >> >>> | mca1 mca2 | >> >>> Object compile: 'test ^''Hello from Object'''. >> >>> (Object >> >>> subclass: #MyClass instanceVariableNames: '' >> >>> classVariableNames: '' >> >>> poolDictionaries: '' >> >>> category: 'Test') >> >>> compile: 'test ^ super halt test, ''my super call lands on >> >>> itself!'''. >> >>> mca1 := ((Smalltalk classNamed: #MyClass)>>#test) >> >>> methodClassAssociation. >> >>> (Smalltalk classNamed: #MyClass) >> >>> rename: 'MyNewAbstraction'. >> >>> mca2 := ((Smalltalk classNamed: #MyNewAbstraction)>>#test) >> >>> methodClassAssociation. >> >>> { mca1. mca2. mca1 == mca2. mca1 == (Smalltalk bindingOf: >> >>> #MyNewAbstraction). mca2 == (Smalltalk bindingOf: #MyNewAbstraction)} >> >>> >> >>> It answers { #MyClass=>nil . #MyClass=>nil . true . false . false} >> >>> i.e. the binding isn't updated, but changes from #MyClass=>MyClass to >> >>> #MyClass=>nil in binding:removedFrom:. >> >>> >> >>> >> >>> -- >> >>> HTH, >> >>> Eliot >> >> >> >> >> >> >> >> >> >> -- >> >> best, >> >> Eliot >> > >> > >> > >> > >> > -- >> > best, >> > Eliot >> > >> > >> > >> > > > > |
In reply to this post by Eliot Miranda-2
On 20.01.2015, at 21:33, Eliot Miranda <[hidden email]> wrote:
> > ** aClass updateMethodBindingsTo: binding. We committed a version that incorporates this, as well as keeping the binding working during class renames (Environments-topa.54, Tests-topa.309). Another fix ensures that the warning about obsolete references still pops up after renaming (Tools-topa.533). - Bert - smime.p7s (5K) Download Attachment |
In reply to this post by Nicolas Cellier
Okay, I found the invalid super-pointer behavior.
It's a lot better with Bert & Tobias' fix, but still there to a smaller degree.. Object compile: 'test ^''Hello from Object'''. (Object subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test') compile: 'test self halt. ^ super test, ''my super call lands on myself!'''. (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test'). (Smalltalk classNamed: #MyClass) new test Do-it on the above. When the debugger appears, simply highlight the code "super test" in the debugger and press "Print It". I expected to see 'Hello from Object' but it seems to be calculating super from the receiver class rather than the method's home class... WITHOUT Bert and Tobias' fix, the above results in the super call truly landing on itself, and if you take the halt out, the tight-recursion I mentioned from teh first paragraph of this thread. WITH their fix, the problem only manifests in the debugger as demonstrated. See, I'm not crazy! :) On Tue, Jan 20, 2015 at 6:05 PM, Nicolas Cellier <[hidden email]> wrote: > > > 2015-01-20 23:56 GMT+01:00 Chris Muller <[hidden email]>: >> >> Hi Eliot, there were TWO problems, Bert and Tobias have fixed one of >> them. The second one is still unfixed in trunk. When you run this >> script and arrive at the debugger, step INTO: >> >> Object compile: 'test ^''Hello from Object'''. >> (Object subclass: #MyClass instanceVariableNames: '' >> classVariableNames: '' poolDictionaries: '' category: 'Test') compile: >> 'test ^ super halt test, ''my super call lands on itself!'''. >> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> (Smalltalk classNamed: #MyNewAbstraction) new test >> > > But it behaves as it should... > You first send halt to super. > If you resume it just answer self. > > Then you send test to self (it's not a super send and never been) > > >> >> then be sure to step INTO the super call to #test. See how it lands >> you in teh same method? THAT bug exists back at least as far back as >> 4.2, so I don't think its Environments related. >> >> I took a look at it and presented my findings in the other email >> thread with subject "The Inbox: Environments-cmm.52.mcz", -- that >> screenshot showing that the bytecodes are teh same and the literal >> binding looks correct. >> >> So I have no idea why its not calling super correctly... >> >> >> On Tue, Jan 20, 2015 at 2:38 PM, Eliot Miranda <[hidden email]> >> wrote: >> > >> > Ugh, I'm behind the times, Tobias you've already fixed it; thanks! >> > Tobias, I like your use of becomeForward:; it is more robust. But I *think* >> > the undeclared removal is misplaced. Don't you think that that code belongs >> > in the BindingPolicy? >> > >> > On Tue, Jan 20, 2015 at 12:33 PM, Eliot Miranda >> > <[hidden email]> wrote: >> >> >> >> >> >> >> >> On Tue, Jan 20, 2015 at 12:26 PM, Eliot Miranda >> >> <[hidden email]> wrote: >> >>> >> >>> Hi Chris, Hi Colin, >> >>> >> >>> >> >>> On Thu, Jan 15, 2015 at 2:48 PM, Chris Muller <[hidden email]> >> >>> wrote: >> >>>> >> >>>> I did a minor class-hierarchy refactoring today which resulted in a >> >>>> an >> >>>> invalid super pointer, resulting in a confusing image lock up due to >> >>>> tight recursion. The script, below, demonstrates the issue in trunk: >> >>>> >> >>>> Object compile: 'test ^''Hello from Object'''. >> >>>> (Object subclass: #MyClass instanceVariableNames: '' >> >>>> classVariableNames: '' poolDictionaries: '' category: 'Test') >> >>>> compile: >> >>>> 'test ^ super halt test, ''my super call lands on myself!'''. >> >>>> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> >>>> ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass >> >>>> instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' >> >>>> category: 'Test'). >> >>>> (Smalltalk classNamed: #MyNewAbstraction) new test >> >>>> >> >>>> But an existing method in the original MyClass had a call to super >> >>>> which now lands in itself, resulting in a tight recursion. >> >>>> >> >>>> The same script without creating the new subclass results in an >> >>>> instant VM crash (both interpreter 2357 and cog 3205): >> >>>> >> >>>> Object compile: 'test ^''Hello from Object'''. >> >>>> (Object subclass: #MyClass instanceVariableNames: '' >> >>>> classVariableNames: '' poolDictionaries: '' category: 'Test') >> >>>> compile: >> >>>> 'test ^ super halt test, ''my super call lands on itself!'''. >> >>>> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> >>>> (Smalltalk classNamed: #MyNewAbstraction) new test >> >>>> >> >>>> I even tried recompiling my entire class hierarchy which was renamed, >> >>>> but it didn't help. >> >>>> >> >>>> How can this be? I _KNOW_ I've used rename class many times in the >> >>>> past... A regression? >> >>> >> >>> >> >>> This is indeed an Environments regression. The issue is where to fix >> >>> the problem. One way to look at it is that >> >>> Environment>>renameClass:from:to: does not update bindings in the renamed >> >>> class's methods. >> >>> >> >>> Here's what the old code did: >> >>> >> >>> SystemDictionary>>renameClass: aClass from: oldName to: newName >> >>> "Rename the class, aClass, to have the title newName." >> >>> >> >>> | oldref category | >> >>> category := SystemOrganization categoryOfElement: oldName. >> >>> self organization classify: newName under: category suppressIfDefault: >> >>> true. >> >>> self organization removeElement: oldName. >> >>> oldref := self associationAt: oldName. >> >>> self removeKey: oldName. >> >>> ** oldref key: newName. >> >>> self add: oldref. "Old association preserves old refs" >> >>> Smalltalk renamedClass: aClass from: oldName to: newName. >> >>> self flushClassNameCache. >> >>> SystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName >> >>> to: newName inCategory: category >> >>> >> >>> The starred line changes the key on the old class's binding, meaning >> >>> that all the methods whose methodClassAssociation is that binding get >> >>> automatically updated (note that class methods have a methodClassAssociation >> >>> that has no key and just points to the class object). >> >>> >> >>> The new code simply forgets to do this: >> >>> >> >>> Environment>>renameClass: aClass from: oldName to: newName >> >>> "Rename the class, aClass, to have the title newName." >> >>> >> >>> | binding category | >> >>> category := self organization categoryOfElement: oldName. >> >>> self organization classify: newName under: category suppressIfDefault: >> >>> true. >> >>> self organization removeElement: oldName. >> >>> binding := self declarationOf: oldName. >> >>> declarations removeKey: oldName. >> >>> self binding: binding removedFrom: self. >> >>> binding := newName => aClass. >> >>> declarations add: binding. >> >>> self binding: binding addedTo: self. >> >>> Smalltalk renamedClass: aClass from: oldName to: newName. >> >>> SystemChangeNotifier uniqueInstance >> >>> classRenamed: aClass >> >>> from: oldName >> >>> to: newName >> >>> inCategory: category >> >>> >> >>> >> >>> But should the change go in Environment>>renameClass:from:to: or in >> >>> the BindingPolicy? i.e. it could be implemented either in >> >>> Environment>>renameClass:from:to:, or in Environment>>showBinding:. I guess >> >>> the former, but I'm cc'ing Colin, because know it?, he wrote it! >> >> >> >> >> >> and if the fix should indeed go in Environment>>renameClass:from:to: , >> >> it is as simple as >> >> >> >> Environment>>renameClass: aClass from: oldName to: newName >> >> "Rename the class, aClass, to have the title newName." >> >> >> >> | binding category | >> >> category := self organization categoryOfElement: oldName. >> >> self organization classify: newName under: category suppressIfDefault: >> >> true. >> >> self organization removeElement: oldName. >> >> binding := self declarationOf: oldName. >> >> declarations removeKey: oldName. >> >> self binding: binding removedFrom: self. >> >> binding := newName => aClass. >> >> declarations add: binding. >> >> self binding: binding addedTo: self. >> >> >> >> ** aClass updateMethodBindingsTo: binding. >> >> Smalltalk renamedClass: aClass from: oldName to: newName. >> >> SystemChangeNotifier uniqueInstance >> >> classRenamed: aClass >> >> from: oldName >> >> to: newName >> >> inCategory: category >> >> >> >> I'll make this change and we can alter later if Colin thinks it's in >> >> the wrong place. >> >> >> >>> >> >>> >> >>> In any case there needs to be a test that checks that a method's >> >>> methodClassAssociation is correctly updated after a rename. I bet Colin >> >>> would have not made this slip had there been a test. >> >>> >> >>> >> >>> Here's the code I used to test this: >> >>> >> >>> | mca1 mca2 | >> >>> Object compile: 'test ^''Hello from Object'''. >> >>> (Object >> >>> subclass: #MyClass instanceVariableNames: '' >> >>> classVariableNames: '' >> >>> poolDictionaries: '' >> >>> category: 'Test') >> >>> compile: 'test ^ super halt test, ''my super call lands on >> >>> itself!'''. >> >>> mca1 := ((Smalltalk classNamed: #MyClass)>>#test) >> >>> methodClassAssociation. >> >>> (Smalltalk classNamed: #MyClass) >> >>> rename: 'MyNewAbstraction'. >> >>> mca2 := ((Smalltalk classNamed: #MyNewAbstraction)>>#test) >> >>> methodClassAssociation. >> >>> { mca1. mca2. mca1 == mca2. mca1 == (Smalltalk bindingOf: >> >>> #MyNewAbstraction). mca2 == (Smalltalk bindingOf: #MyNewAbstraction)} >> >>> >> >>> It answers { #MyClass=>nil . #MyClass=>nil . true . false . false} >> >>> i.e. the binding isn't updated, but changes from #MyClass=>MyClass to >> >>> #MyClass=>nil in binding:removedFrom:. >> >>> >> >>> >> >>> -- >> >>> HTH, >> >>> Eliot >> >> >> >> >> >> >> >> >> >> -- >> >> best, >> >> Eliot >> > >> > >> > >> > >> > -- >> > best, >> > Eliot >> > >> > >> > >> > > > > |
Hi Chris
On 21.01.2015, at 17:39, Chris Muller <[hidden email]> wrote: > Okay, I found the invalid super-pointer behavior. > > It's a lot better with Bert & Tobias' fix, but still there to a smaller degree.. > > Object compile: 'test ^''Hello from Object'''. > (Object subclass: #MyClass instanceVariableNames: '' > classVariableNames: '' poolDictionaries: '' category: 'Test') compile: > 'test self halt. ^ super test, ''my super call lands on myself!'''. > (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. > ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass > instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' > category: 'Test'). > (Smalltalk classNamed: #MyClass) new test > > Do-it on the above. When the debugger appears, simply highlight the > code "super test" in the debugger and press "Print It". > > I expected to see 'Hello from Object' but it seems to be calculating > super from the receiver class rather than the method's home class... > > WITHOUT Bert and Tobias' fix, the above results in the super call > truly landing on itself, and if you take the halt out, the > tight-recursion I mentioned from teh first paragraph of this thread. > WITH their fix, the problem only manifests in the debugger as > demonstrated. _Only_ if you select 'super test' and PrintIt (or DoIt), the apparent “recursion” is triggered. This is due to the way DoIt work, they compile an anonymous class that are “homed” in the receivers class, in this case MyClass. Hence, super ends up in MyNewAbstraction[1]. Yes, this is a bit surprising, but I don't know whether it is wrong. Compiler>>evaluate:in:to:notifying:ifFail:logged: calculates the home class of the DoIt via this: | theClass | theClass := ((aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class). that is, the _Receiver_ of the context, not the home class of the context's method. @Bert, Eliot: Which one do you think would be correct? the Stack is down below[1]. Best -Tobias [1]: Compiler>>evaluateCue:ifFail: Receiver: a Compiler Arguments and temporary variables: aCue: a CompilationCue failBlock: [closure] in Compiler>>evaluateCue:ifFail:logged: methodNode: DoItIn: ThisContext ^ super test method: (MyClass>>#DoItIn: "a CompiledMethod(374)") value: nil Receiver's instance variables: parser: a Parser cue: a CompilationCue Compiler>>evaluateCue:ifFail:logged: Receiver: a Compiler Arguments and temporary variables: aCue: a CompilationCue failBlock: [closure] in [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAnd...etc... logFlag: true value: nil Receiver's instance variables: parser: a Parser cue: a CompilationCue Compiler>>evaluate:in:to:notifying:ifFail:logged: Receiver: a Compiler Arguments and temporary variables: textOrStream: a ReadStream aContext: MyClass(MyNewAbstraction)>>test receiver: a MyClass aRequestor: a SmalltalkEditor failBlock: [closure] in [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAnd...etc... logFlag: true theClass: MyClass Receiver's instance variables: parser: a Parser cue: a CompilationCue [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: Receiver: a SmalltalkEditor Arguments and temporary variables: <<error during printing> Receiver's instance variables: morph: a TextMorphForEditView(3464) selectionShowing: false model: a Debugger paragraph: a NewParagraph markBlock: a CharacterBlock with index 21 and character $s and rectangle 110@0 ...etc... pointBlock: a CharacterBlock with index 31 and character $, and rectangle 174@0...etc... beginTypeInIndex: nil emphasisHere: {a TextColor code: (Color r: 0.0 g: 0.0 b: 0.5)} lastParenLocation: nil otherInterval: (20 to: 19) oldInterval: (20 to: 19) typeAhead: nil styler: nil BlockClosure>>on:do: Receiver: [closure] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: Arguments and temporary variables: exception: OutOfScopeNotification handlerAction: [closure] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo...etc... handlerActive: true Receiver's instance variables: outerContext: SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: startpc: 97 numArgs: 0 SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: Receiver: a SmalltalkEditor Arguments and temporary variables: aBlock: [closure] in [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt result: nil rcvr: a MyClass ctxt: MyClass(MyNewAbstraction)>>test Receiver's instance variables: morph: a TextMorphForEditView(3464) selectionShowing: false model: a Debugger paragraph: a NewParagraph markBlock: a CharacterBlock with index 21 and character $s and rectangle 110@0 ...etc... pointBlock: a CharacterBlock with index 31 and character $, and rectangle 174@0...etc... beginTypeInIndex: nil emphasisHere: {a TextColor code: (Color r: 0.0 g: 0.0 b: 0.5)} lastParenLocation: nil otherInterval: (20 to: 19) oldInterval: (20 to: 19) typeAhead: nil styler: nil [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt Receiver: a PluggableTextMorphPlus(473) Arguments and temporary variables: oldEditor: {a SmalltalkEditor} Receiver's instance variables: bounds: 36@380 corner: 740@592 owner: a PluggablePanelMorph(3130) submorphs: {a ScrollBar(1013) . a TransformMorph(3047)} fullBounds: 36@380 corner: 740@592 color: Color white extension: a MorphExtension (3891) [other: (layoutFrame -> a LayoutFrame) (vSc...etc... borderWidth: 1 borderColor: Color lightGray model: a Debugger slotName: nil open: false scrollBar: a ScrollBar(1013) scroller: a TransformMorph(3047) retractableScrollBar: false scrollBarOnLeft: false getMenuSelector: #codePaneMenu:shifted: getMenuTitleSelector: nil scrollBarHidden: nil hasFocus: false hScrollBar: a ScrollBar(2030) textMorph: a TextMorphForEditView(3464) getTextSelector: #contents setTextSelector: #contents:notifying: getSelectionSelector: #contentsSelection hasUnacceptedEdits: false askBeforeDiscardingEdits: true selectionInterval: (21 to: 30) hasEditingConflicts: false getColorSelector: nil acceptAction: nil unstyledAcceptText: nil styler: a SHTextStylerST80 TextMorphForEditView(TextMorph)>>handleEdit: Receiver: a TextMorphForEditView(3464) Arguments and temporary variables: editBlock: [closure] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt result: nil Receiver's instance variables: bounds: 0@0 corner: 683@18 owner: a TransformMorph(3047) submorphs: #() fullBounds: 0@0 corner: 683@18 color: Color black extension: a MorphExtension (3814) [other: (blinkStart -> 1091554)] borderWidth: 0 borderColor: Color black textStyle: a TextStyle Bitmap DejaVu Sans 9 text: a Text for 'test self halt. ^ super test, ''my super call lands on myse...etc... wrapFlag: true paragraph: a NewParagraph editor: a SmalltalkEditor container: nil predecessor: nil successor: nil backgroundColor: nil margins: nil editHistory: nil editView: a PluggableTextMorphPlus(473) acceptOnCR: false PluggableTextMorphPlus(PluggableTextMorph)>>printIt Receiver: a PluggableTextMorphPlus(473) Arguments and temporary variables: oldEditor: {a SmalltalkEditor} Receiver's instance variables: bounds: 36@380 corner: 740@592 owner: a PluggablePanelMorph(3130) submorphs: {a ScrollBar(1013) . a TransformMorph(3047)} fullBounds: 36@380 corner: 740@592 color: Color white extension: a MorphExtension (3891) [other: (layoutFrame -> a LayoutFrame) (vSc...etc... borderWidth: 1 borderColor: Color lightGray model: a Debugger slotName: nil open: false scrollBar: a ScrollBar(1013) scroller: a TransformMorph(3047) retractableScrollBar: false scrollBarOnLeft: false getMenuSelector: #codePaneMenu:shifted: getMenuTitleSelector: nil scrollBarHidden: nil hasFocus: false hScrollBar: a ScrollBar(2030) textMorph: a TextMorphForEditView(3464) getTextSelector: #contents setTextSelector: #contents:notifying: getSelectionSelector: #contentsSelection hasUnacceptedEdits: false askBeforeDiscardingEdits: true selectionInterval: (21 to: 30) hasEditingConflicts: false getColorSelector: nil acceptAction: nil unstyledAcceptText: nil styler: a SHTextStylerST80 Debugger(StringHolder)>>perform:orSendTo: Receiver: a Debugger Arguments and temporary variables: selector: #printIt otherTarget: a PluggableTextMorphPlus(473) Receiver's instance variables: dependents: a DependentsArray(a PluggableSystemWindow(1857) a PluggableListMorp...etc... contents: a Text for 'test self halt. ^ super test, ''my super call lands on ...etc... currentCompiledMethod: nil contentsSymbol: #source multiWindowState: nil interruptedProcess: a Process in Debugger class>>morphicOpenOn:context:label:co...etc... interruptedController: nil contextStack: an OrderedCollection(MyClass(Object)>>halt MyClass(MyNewAbstracti...etc... contextStackIndex: 2 contextStackList: an OrderedCollection('MyClass(Object)>>halt' 'MyClass(MyNewAb...etc... receiverInspector: an Inspector contextVariablesInspector: a ContextVariablesInspector externalInterrupt: false proceedValue: nil selectingPC: true savedCursor: ((CursorWithMask extent: 16@16 depth: 1 fromArray: #( 2r0 2...etc... isolationHead: nil failedProject: nil errorWasInUIProcess: true labelString: nil message: nil untilExpression: nil Debugger>>perform:orSendTo: Receiver: a Debugger Arguments and temporary variables: selector: #printIt otherTarget: a PluggableTextMorphPlus(473) result: nil Receiver's instance variables: dependents: a DependentsArray(a PluggableSystemWindow(1857) a PluggableListMorp...etc... contents: a Text for 'test self halt. ^ super test, ''my super call lands on ...etc... currentCompiledMethod: nil contentsSymbol: #source multiWindowState: nil interruptedProcess: a Process in Debugger class>>morphicOpenOn:context:label:co...etc... interruptedController: nil contextStack: an OrderedCollection(MyClass(Object)>>halt MyClass(MyNewAbstracti...etc... contextStackIndex: 2 contextStackList: an OrderedCollection('MyClass(Object)>>halt' 'MyClass(MyNewAb...etc... receiverInspector: an Inspector contextVariablesInspector: a ContextVariablesInspector externalInterrupt: false proceedValue: nil selectingPC: true savedCursor: ((CursorWithMask extent: 16@16 depth: 1 fromArray: #( 2r0 2...etc... isolationHead: nil failedProject: nil errorWasInUIProcess: true labelString: nil message: nil untilExpression: nil MenuItemMorph>>DoIt Receiver: a MenuItemMorph(77)'print it (p)' Arguments and temporary variables: Receiver's instance variables: bounds: 216@558 corner: 359@576 owner: a MenuMorph(2209) submorphs: #() fullBounds: 216@558 corner: 359@576 color: Color black extension: a MorphExtension (264) [other: (layoutProperties -> a LayoutPropert...etc... font: a StrikeFont(Bitmap DejaVu Sans 9 14) emphasis: 0 contents: 'print it (p)' hasFocus: false isEnabled: true subMenu: nil isSelected: false target: a Debugger selector: #perform:orSendTo: arguments: {#printIt . a PluggableTextMorphPlus(473)} icon: Form(16x16x32) lastMousePosition: nil CompiledMethod>>valueWithReceiver:arguments: Receiver: (MenuItemMorph>>#DoIt "a CompiledMethod(1420)") Arguments and temporary variables: aReceiver: a MenuItemMorph(77)'print it (p)' anArray: #() Receiver's instance variables: (MenuItemMorph>>#DoIt "a CompiledMethod(1420)") [] in SmalltalkEditor(TextEditor)>>debug:receiver:in: Receiver: a SmalltalkEditor Arguments and temporary variables: <<error during printing> Receiver's instance variables: morph: a TextMorphForEditView(4064) selectionShowing: false model: an ObjectExplorer paragraph: a NewParagraph markBlock: a CharacterBlock with index 1 and character $s and rectangle 0@0 cor...etc... pointBlock: a CharacterBlock with index 62 and rectangle 366@0 corner: 366@16 ...etc... beginTypeInIndex: nil emphasisHere: {a TextFontChange font: 2} lastParenLocation: nil otherInterval: (61 to: 61) oldInterval: (55 to: 54) typeAhead: a WriteStream styler: nil [] in BlockClosure>>newProcess Receiver: [closure] in SmalltalkEditor(TextEditor)>>debug:receiver:in: Arguments and temporary variables: Receiver's instance variables: outerContext: SmalltalkEditor(TextEditor)>>debug:receiver:in: startpc: 112 numArgs: 0 --- The full stack --- Compiler>>evaluateCue:ifFail: Compiler>>evaluateCue:ifFail:logged: Compiler>>evaluate:in:to:notifying:ifFail:logged: [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: BlockClosure>>on:do: SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt TextMorphForEditView(TextMorph)>>handleEdit: PluggableTextMorphPlus(PluggableTextMorph)>>printIt Debugger(StringHolder)>>perform:orSendTo: Debugger>>perform:orSendTo: MenuItemMorph>>DoIt CompiledMethod>>valueWithReceiver:arguments: [] in SmalltalkEditor(TextEditor)>>debug:receiver:in: [] in BlockClosure>>newProcess signature.asc (1K) Download Attachment |
In reply to this post by Chris Muller-3
On 21-01-2015, at 8:39 AM, Chris Muller <[hidden email]> wrote: > See, I'm not crazy! :) Let’s not get ahead of ourselves here. Clearly, you *are* crazy, but in this case you’re not wrong. There’s an important difference. After all, being wrong is a bad thing. tim -- tim Rowledge; [hidden email]; http://www.rowledge.org/tim Useful random insult:- One clown short of a circus. |
In reply to this post by Tobias Pape
Hi Tobias,
On Wed, Jan 21, 2015 at 10:24 AM, Tobias Pape <[hidden email]> wrote: Hi Chris Yes, well found. Whereas if we used | theClass | theClass := aContext ifNil: [receiver class] ifFalse: [aContext methodClass] we would get the behaviour Chris is (rightly) expecting.
So neither :-). I think the correct code is as I wrote above, the receiver's class if no context, otherwise the context's methodClass (which of course is derived from the context's method).
best,
Eliot |
In reply to this post by Tobias Pape
On Wed, Jan 21, 2015 at 12:24 PM, Tobias Pape <[hidden email]> wrote:
> Hi Chris > > On 21.01.2015, at 17:39, Chris Muller <[hidden email]> wrote: > >> Okay, I found the invalid super-pointer behavior. >> >> It's a lot better with Bert & Tobias' fix, but still there to a smaller degree.. >> >> Object compile: 'test ^''Hello from Object'''. >> (Object subclass: #MyClass instanceVariableNames: '' >> classVariableNames: '' poolDictionaries: '' category: 'Test') compile: >> 'test self halt. ^ super test, ''my super call lands on myself!'''. >> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >> ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass >> instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' >> category: 'Test'). >> (Smalltalk classNamed: #MyClass) new test >> >> Do-it on the above. When the debugger appears, simply highlight the >> code "super test" in the debugger and press "Print It". >> >> I expected to see 'Hello from Object' but it seems to be calculating >> super from the receiver class rather than the method's home class... >> >> WITHOUT Bert and Tobias' fix, the above results in the super call >> truly landing on itself, and if you take the halt out, the >> tight-recursion I mentioned from teh first paragraph of this thread. >> WITH their fix, the problem only manifests in the debugger as >> demonstrated. > > If you hit step-into, you actually end up in the Superclass. > _Only_ if you select 'super test' and PrintIt (or DoIt), the > apparent “recursion” is triggered. > This is due to the way DoIt work, they compile an anonymous class > that are “homed” in the receivers class, in this case MyClass. Hence, > super ends up in MyNewAbstraction[1]. > Yes, this is a bit surprising, but I don't know whether it is wrong. It is inconsistent than if you did not do the rename: Object compile: 'test ^''Hello from Object'''. (Object subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test') compile: 'test self halt. ^ super test, ''my super call lands on myself!'''. (Smalltalk classNamed: #MyClass) new test This time, inside the debugger, "super test" reports the expected 'Hello from Object'. So, _something_ must be different in the renamed class..? > > > Compiler>>evaluate:in:to:notifying:ifFail:logged: > > calculates the home class of the DoIt via this: > > | theClass | > theClass := ((aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class). > > that is, the _Receiver_ of the context, not the home class of the context's method. > > @Bert, Eliot: Which one do you think would be correct? the Stack is down below[1]. > > > > Best > -Tobias > > > [1]: > > Compiler>>evaluateCue:ifFail: > Receiver: a Compiler > Arguments and temporary variables: > aCue: a CompilationCue > failBlock: [closure] in Compiler>>evaluateCue:ifFail:logged: > methodNode: DoItIn: ThisContext > ^ super test > method: (MyClass>>#DoItIn: "a CompiledMethod(374)") > value: nil > Receiver's instance variables: > parser: a Parser > cue: a CompilationCue > > Compiler>>evaluateCue:ifFail:logged: > Receiver: a Compiler > Arguments and temporary variables: > aCue: a CompilationCue > failBlock: [closure] in [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAnd...etc... > logFlag: true > value: nil > Receiver's instance variables: > parser: a Parser > cue: a CompilationCue > > Compiler>>evaluate:in:to:notifying:ifFail:logged: > Receiver: a Compiler > Arguments and temporary variables: > textOrStream: a ReadStream > aContext: MyClass(MyNewAbstraction)>>test > receiver: a MyClass > aRequestor: a SmalltalkEditor > failBlock: [closure] in [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAnd...etc... > logFlag: true > theClass: MyClass > Receiver's instance variables: > parser: a Parser > cue: a CompilationCue > > [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: > Receiver: a SmalltalkEditor > Arguments and temporary variables: > <<error during printing> > Receiver's instance variables: > morph: a TextMorphForEditView(3464) > selectionShowing: false > model: a Debugger > paragraph: a NewParagraph > markBlock: a CharacterBlock with index 21 and character $s and rectangle 110@0 ...etc... > pointBlock: a CharacterBlock with index 31 and character $, and rectangle 174@0...etc... > beginTypeInIndex: nil > emphasisHere: {a TextColor code: (Color r: 0.0 g: 0.0 b: 0.5)} > lastParenLocation: nil > otherInterval: (20 to: 19) > oldInterval: (20 to: 19) > typeAhead: nil > styler: nil > > BlockClosure>>on:do: > Receiver: [closure] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: > Arguments and temporary variables: > exception: OutOfScopeNotification > handlerAction: [closure] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo...etc... > handlerActive: true > Receiver's instance variables: > outerContext: SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: > startpc: 97 > numArgs: 0 > > SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: > Receiver: a SmalltalkEditor > Arguments and temporary variables: > aBlock: [closure] in [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt > result: nil > rcvr: a MyClass > ctxt: MyClass(MyNewAbstraction)>>test > Receiver's instance variables: > morph: a TextMorphForEditView(3464) > selectionShowing: false > model: a Debugger > paragraph: a NewParagraph > markBlock: a CharacterBlock with index 21 and character $s and rectangle 110@0 ...etc... > pointBlock: a CharacterBlock with index 31 and character $, and rectangle 174@0...etc... > beginTypeInIndex: nil > emphasisHere: {a TextColor code: (Color r: 0.0 g: 0.0 b: 0.5)} > lastParenLocation: nil > otherInterval: (20 to: 19) > oldInterval: (20 to: 19) > typeAhead: nil > styler: nil > > [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt > Receiver: a PluggableTextMorphPlus(473) > Arguments and temporary variables: > oldEditor: {a SmalltalkEditor} > Receiver's instance variables: > bounds: 36@380 corner: 740@592 > owner: a PluggablePanelMorph(3130) > submorphs: {a ScrollBar(1013) . a TransformMorph(3047)} > fullBounds: 36@380 corner: 740@592 > color: Color white > extension: a MorphExtension (3891) [other: (layoutFrame -> a LayoutFrame) (vSc...etc... > borderWidth: 1 > borderColor: Color lightGray > model: a Debugger > slotName: nil > open: false > scrollBar: a ScrollBar(1013) > scroller: a TransformMorph(3047) > retractableScrollBar: false > scrollBarOnLeft: false > getMenuSelector: #codePaneMenu:shifted: > getMenuTitleSelector: nil > scrollBarHidden: nil > hasFocus: false > hScrollBar: a ScrollBar(2030) > textMorph: a TextMorphForEditView(3464) > getTextSelector: #contents > setTextSelector: #contents:notifying: > getSelectionSelector: #contentsSelection > hasUnacceptedEdits: false > askBeforeDiscardingEdits: true > selectionInterval: (21 to: 30) > hasEditingConflicts: false > getColorSelector: nil > acceptAction: nil > unstyledAcceptText: nil > styler: a SHTextStylerST80 > > TextMorphForEditView(TextMorph)>>handleEdit: > Receiver: a TextMorphForEditView(3464) > Arguments and temporary variables: > editBlock: [closure] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt > result: nil > Receiver's instance variables: > bounds: 0@0 corner: 683@18 > owner: a TransformMorph(3047) > submorphs: #() > fullBounds: 0@0 corner: 683@18 > color: Color black > extension: a MorphExtension (3814) [other: (blinkStart -> 1091554)] > borderWidth: 0 > borderColor: Color black > textStyle: a TextStyle Bitmap DejaVu Sans 9 > text: a Text for 'test self halt. ^ super test, ''my super call lands on myse...etc... > wrapFlag: true > paragraph: a NewParagraph > editor: a SmalltalkEditor > container: nil > predecessor: nil > successor: nil > backgroundColor: nil > margins: nil > editHistory: nil > editView: a PluggableTextMorphPlus(473) > acceptOnCR: false > > PluggableTextMorphPlus(PluggableTextMorph)>>printIt > Receiver: a PluggableTextMorphPlus(473) > Arguments and temporary variables: > oldEditor: {a SmalltalkEditor} > Receiver's instance variables: > bounds: 36@380 corner: 740@592 > owner: a PluggablePanelMorph(3130) > submorphs: {a ScrollBar(1013) . a TransformMorph(3047)} > fullBounds: 36@380 corner: 740@592 > color: Color white > extension: a MorphExtension (3891) [other: (layoutFrame -> a LayoutFrame) (vSc...etc... > borderWidth: 1 > borderColor: Color lightGray > model: a Debugger > slotName: nil > open: false > scrollBar: a ScrollBar(1013) > scroller: a TransformMorph(3047) > retractableScrollBar: false > scrollBarOnLeft: false > getMenuSelector: #codePaneMenu:shifted: > getMenuTitleSelector: nil > scrollBarHidden: nil > hasFocus: false > hScrollBar: a ScrollBar(2030) > textMorph: a TextMorphForEditView(3464) > getTextSelector: #contents > setTextSelector: #contents:notifying: > getSelectionSelector: #contentsSelection > hasUnacceptedEdits: false > askBeforeDiscardingEdits: true > selectionInterval: (21 to: 30) > hasEditingConflicts: false > getColorSelector: nil > acceptAction: nil > unstyledAcceptText: nil > styler: a SHTextStylerST80 > > Debugger(StringHolder)>>perform:orSendTo: > Receiver: a Debugger > Arguments and temporary variables: > selector: #printIt > otherTarget: a PluggableTextMorphPlus(473) > Receiver's instance variables: > dependents: a DependentsArray(a PluggableSystemWindow(1857) a PluggableListMorp...etc... > contents: a Text for 'test self halt. ^ super test, ''my super call lands on ...etc... > currentCompiledMethod: nil > contentsSymbol: #source > multiWindowState: nil > interruptedProcess: a Process in Debugger class>>morphicOpenOn:context:label:co...etc... > interruptedController: nil > contextStack: an OrderedCollection(MyClass(Object)>>halt MyClass(MyNewAbstracti...etc... > contextStackIndex: 2 > contextStackList: an OrderedCollection('MyClass(Object)>>halt' 'MyClass(MyNewAb...etc... > receiverInspector: an Inspector > contextVariablesInspector: a ContextVariablesInspector > externalInterrupt: false > proceedValue: nil > selectingPC: true > savedCursor: ((CursorWithMask > extent: 16@16 > depth: 1 > fromArray: #( > 2r0 > 2...etc... > isolationHead: nil > failedProject: nil > errorWasInUIProcess: true > labelString: nil > message: nil > untilExpression: nil > > Debugger>>perform:orSendTo: > Receiver: a Debugger > Arguments and temporary variables: > selector: #printIt > otherTarget: a PluggableTextMorphPlus(473) > result: nil > Receiver's instance variables: > dependents: a DependentsArray(a PluggableSystemWindow(1857) a PluggableListMorp...etc... > contents: a Text for 'test self halt. ^ super test, ''my super call lands on ...etc... > currentCompiledMethod: nil > contentsSymbol: #source > multiWindowState: nil > interruptedProcess: a Process in Debugger class>>morphicOpenOn:context:label:co...etc... > interruptedController: nil > contextStack: an OrderedCollection(MyClass(Object)>>halt MyClass(MyNewAbstracti...etc... > contextStackIndex: 2 > contextStackList: an OrderedCollection('MyClass(Object)>>halt' 'MyClass(MyNewAb...etc... > receiverInspector: an Inspector > contextVariablesInspector: a ContextVariablesInspector > externalInterrupt: false > proceedValue: nil > selectingPC: true > savedCursor: ((CursorWithMask > extent: 16@16 > depth: 1 > fromArray: #( > 2r0 > 2...etc... > isolationHead: nil > failedProject: nil > errorWasInUIProcess: true > labelString: nil > message: nil > untilExpression: nil > > MenuItemMorph>>DoIt > Receiver: a MenuItemMorph(77)'print it (p)' > Arguments and temporary variables: > > Receiver's instance variables: > bounds: 216@558 corner: 359@576 > owner: a MenuMorph(2209) > submorphs: #() > fullBounds: 216@558 corner: 359@576 > color: Color black > extension: a MorphExtension (264) [other: (layoutProperties -> a LayoutPropert...etc... > font: a StrikeFont(Bitmap DejaVu Sans 9 14) > emphasis: 0 > contents: 'print it (p)' > hasFocus: false > isEnabled: true > subMenu: nil > isSelected: false > target: a Debugger > selector: #perform:orSendTo: > arguments: {#printIt . a PluggableTextMorphPlus(473)} > icon: Form(16x16x32) > lastMousePosition: nil > > CompiledMethod>>valueWithReceiver:arguments: > Receiver: (MenuItemMorph>>#DoIt "a CompiledMethod(1420)") > Arguments and temporary variables: > aReceiver: a MenuItemMorph(77)'print it (p)' > anArray: #() > Receiver's instance variables: > (MenuItemMorph>>#DoIt "a CompiledMethod(1420)") > > [] in SmalltalkEditor(TextEditor)>>debug:receiver:in: > Receiver: a SmalltalkEditor > Arguments and temporary variables: > <<error during printing> > Receiver's instance variables: > morph: a TextMorphForEditView(4064) > selectionShowing: false > model: an ObjectExplorer > paragraph: a NewParagraph > markBlock: a CharacterBlock with index 1 and character $s and rectangle 0@0 cor...etc... > pointBlock: a CharacterBlock with index 62 and rectangle 366@0 corner: 366@16 > ...etc... > beginTypeInIndex: nil > emphasisHere: {a TextFontChange font: 2} > lastParenLocation: nil > otherInterval: (61 to: 61) > oldInterval: (55 to: 54) > typeAhead: a WriteStream > styler: nil > > [] in BlockClosure>>newProcess > Receiver: [closure] in SmalltalkEditor(TextEditor)>>debug:receiver:in: > Arguments and temporary variables: > > Receiver's instance variables: > outerContext: SmalltalkEditor(TextEditor)>>debug:receiver:in: > startpc: 112 > numArgs: 0 > > > --- The full stack --- > Compiler>>evaluateCue:ifFail: > Compiler>>evaluateCue:ifFail:logged: > Compiler>>evaluate:in:to:notifying:ifFail:logged: > [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: > BlockClosure>>on:do: > SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: > [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt > TextMorphForEditView(TextMorph)>>handleEdit: > PluggableTextMorphPlus(PluggableTextMorph)>>printIt > Debugger(StringHolder)>>perform:orSendTo: > Debugger>>perform:orSendTo: > MenuItemMorph>>DoIt > CompiledMethod>>valueWithReceiver:arguments: > [] in SmalltalkEditor(TextEditor)>>debug:receiver:in: > [] in BlockClosure>>newProcess > > > > |
Okay, I got it. It's not the rename, the reason it worked was because
it was not an instance of a further subclass. As demonstrated by [1]. DoIt processing calculates "super" of the receiver's class, not the methodHome's class. Just what you said. As far as everyday debugging, I've never noticed this behavior in 21 years of Smalltalking. When I was debugging yesterday and the code of my superclass method was one-line "^true" and I got false back --- it was surreal. Well found indeed, thanks for fixing. [1] -- Same script but instantiate MySubclass (under MyClass) instead. Object compile: 'test ^''Hello from Object'''. (Object subclass: #MyClass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test') compile: 'test self halt. ^ super test, ''my super call lands on myself!'''. ((Smalltalk classNamed: #MyClass) subclass: #MySubclass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Test'). (Smalltalk classNamed: #MySubclass) new test On Wed, Jan 21, 2015 at 1:20 PM, Chris Muller <[hidden email]> wrote: > On Wed, Jan 21, 2015 at 12:24 PM, Tobias Pape <[hidden email]> wrote: >> Hi Chris >> >> On 21.01.2015, at 17:39, Chris Muller <[hidden email]> wrote: >> >>> Okay, I found the invalid super-pointer behavior. >>> >>> It's a lot better with Bert & Tobias' fix, but still there to a smaller degree.. >>> >>> Object compile: 'test ^''Hello from Object'''. >>> (Object subclass: #MyClass instanceVariableNames: '' >>> classVariableNames: '' poolDictionaries: '' category: 'Test') compile: >>> 'test self halt. ^ super test, ''my super call lands on myself!'''. >>> (Smalltalk classNamed: #MyClass) rename: 'MyNewAbstraction'. >>> ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass >>> instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' >>> category: 'Test'). >>> (Smalltalk classNamed: #MyClass) new test >>> >>> Do-it on the above. When the debugger appears, simply highlight the >>> code "super test" in the debugger and press "Print It". >>> >>> I expected to see 'Hello from Object' but it seems to be calculating >>> super from the receiver class rather than the method's home class... >>> >>> WITHOUT Bert and Tobias' fix, the above results in the super call >>> truly landing on itself, and if you take the halt out, the >>> tight-recursion I mentioned from teh first paragraph of this thread. >>> WITH their fix, the problem only manifests in the debugger as >>> demonstrated. >> >> If you hit step-into, you actually end up in the Superclass. >> _Only_ if you select 'super test' and PrintIt (or DoIt), the >> apparent “recursion” is triggered. >> This is due to the way DoIt work, they compile an anonymous class >> that are “homed” in the receivers class, in this case MyClass. Hence, >> super ends up in MyNewAbstraction[1]. >> Yes, this is a bit surprising, but I don't know whether it is wrong. > > It is inconsistent than if you did not do the rename: > > Object compile: 'test ^''Hello from Object'''. > (Object subclass: #MyClass instanceVariableNames: '' > classVariableNames: '' poolDictionaries: '' category: 'Test') compile: > 'test self halt. ^ super test, ''my super call lands on myself!'''. > (Smalltalk classNamed: #MyClass) new test > > This time, inside the debugger, "super test" reports the expected > 'Hello from Object'. > > So, _something_ must be different in the renamed class..? > > > >> >> >> Compiler>>evaluate:in:to:notifying:ifFail:logged: >> >> calculates the home class of the DoIt via this: >> >> | theClass | >> theClass := ((aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class). >> >> that is, the _Receiver_ of the context, not the home class of the context's method. >> >> @Bert, Eliot: Which one do you think would be correct? the Stack is down below[1]. >> >> >> >> Best >> -Tobias >> >> >> [1]: >> >> Compiler>>evaluateCue:ifFail: >> Receiver: a Compiler >> Arguments and temporary variables: >> aCue: a CompilationCue >> failBlock: [closure] in Compiler>>evaluateCue:ifFail:logged: >> methodNode: DoItIn: ThisContext >> ^ super test >> method: (MyClass>>#DoItIn: "a CompiledMethod(374)") >> value: nil >> Receiver's instance variables: >> parser: a Parser >> cue: a CompilationCue >> >> Compiler>>evaluateCue:ifFail:logged: >> Receiver: a Compiler >> Arguments and temporary variables: >> aCue: a CompilationCue >> failBlock: [closure] in [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAnd...etc... >> logFlag: true >> value: nil >> Receiver's instance variables: >> parser: a Parser >> cue: a CompilationCue >> >> Compiler>>evaluate:in:to:notifying:ifFail:logged: >> Receiver: a Compiler >> Arguments and temporary variables: >> textOrStream: a ReadStream >> aContext: MyClass(MyNewAbstraction)>>test >> receiver: a MyClass >> aRequestor: a SmalltalkEditor >> failBlock: [closure] in [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAnd...etc... >> logFlag: true >> theClass: MyClass >> Receiver's instance variables: >> parser: a Parser >> cue: a CompilationCue >> >> [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: >> Receiver: a SmalltalkEditor >> Arguments and temporary variables: >> <<error during printing> >> Receiver's instance variables: >> morph: a TextMorphForEditView(3464) >> selectionShowing: false >> model: a Debugger >> paragraph: a NewParagraph >> markBlock: a CharacterBlock with index 21 and character $s and rectangle 110@0 ...etc... >> pointBlock: a CharacterBlock with index 31 and character $, and rectangle 174@0...etc... >> beginTypeInIndex: nil >> emphasisHere: {a TextColor code: (Color r: 0.0 g: 0.0 b: 0.5)} >> lastParenLocation: nil >> otherInterval: (20 to: 19) >> oldInterval: (20 to: 19) >> typeAhead: nil >> styler: nil >> >> BlockClosure>>on:do: >> Receiver: [closure] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: >> Arguments and temporary variables: >> exception: OutOfScopeNotification >> handlerAction: [closure] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo...etc... >> handlerActive: true >> Receiver's instance variables: >> outerContext: SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: >> startpc: 97 >> numArgs: 0 >> >> SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: >> Receiver: a SmalltalkEditor >> Arguments and temporary variables: >> aBlock: [closure] in [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt >> result: nil >> rcvr: a MyClass >> ctxt: MyClass(MyNewAbstraction)>>test >> Receiver's instance variables: >> morph: a TextMorphForEditView(3464) >> selectionShowing: false >> model: a Debugger >> paragraph: a NewParagraph >> markBlock: a CharacterBlock with index 21 and character $s and rectangle 110@0 ...etc... >> pointBlock: a CharacterBlock with index 31 and character $, and rectangle 174@0...etc... >> beginTypeInIndex: nil >> emphasisHere: {a TextColor code: (Color r: 0.0 g: 0.0 b: 0.5)} >> lastParenLocation: nil >> otherInterval: (20 to: 19) >> oldInterval: (20 to: 19) >> typeAhead: nil >> styler: nil >> >> [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt >> Receiver: a PluggableTextMorphPlus(473) >> Arguments and temporary variables: >> oldEditor: {a SmalltalkEditor} >> Receiver's instance variables: >> bounds: 36@380 corner: 740@592 >> owner: a PluggablePanelMorph(3130) >> submorphs: {a ScrollBar(1013) . a TransformMorph(3047)} >> fullBounds: 36@380 corner: 740@592 >> color: Color white >> extension: a MorphExtension (3891) [other: (layoutFrame -> a LayoutFrame) (vSc...etc... >> borderWidth: 1 >> borderColor: Color lightGray >> model: a Debugger >> slotName: nil >> open: false >> scrollBar: a ScrollBar(1013) >> scroller: a TransformMorph(3047) >> retractableScrollBar: false >> scrollBarOnLeft: false >> getMenuSelector: #codePaneMenu:shifted: >> getMenuTitleSelector: nil >> scrollBarHidden: nil >> hasFocus: false >> hScrollBar: a ScrollBar(2030) >> textMorph: a TextMorphForEditView(3464) >> getTextSelector: #contents >> setTextSelector: #contents:notifying: >> getSelectionSelector: #contentsSelection >> hasUnacceptedEdits: false >> askBeforeDiscardingEdits: true >> selectionInterval: (21 to: 30) >> hasEditingConflicts: false >> getColorSelector: nil >> acceptAction: nil >> unstyledAcceptText: nil >> styler: a SHTextStylerST80 >> >> TextMorphForEditView(TextMorph)>>handleEdit: >> Receiver: a TextMorphForEditView(3464) >> Arguments and temporary variables: >> editBlock: [closure] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt >> result: nil >> Receiver's instance variables: >> bounds: 0@0 corner: 683@18 >> owner: a TransformMorph(3047) >> submorphs: #() >> fullBounds: 0@0 corner: 683@18 >> color: Color black >> extension: a MorphExtension (3814) [other: (blinkStart -> 1091554)] >> borderWidth: 0 >> borderColor: Color black >> textStyle: a TextStyle Bitmap DejaVu Sans 9 >> text: a Text for 'test self halt. ^ super test, ''my super call lands on myse...etc... >> wrapFlag: true >> paragraph: a NewParagraph >> editor: a SmalltalkEditor >> container: nil >> predecessor: nil >> successor: nil >> backgroundColor: nil >> margins: nil >> editHistory: nil >> editView: a PluggableTextMorphPlus(473) >> acceptOnCR: false >> >> PluggableTextMorphPlus(PluggableTextMorph)>>printIt >> Receiver: a PluggableTextMorphPlus(473) >> Arguments and temporary variables: >> oldEditor: {a SmalltalkEditor} >> Receiver's instance variables: >> bounds: 36@380 corner: 740@592 >> owner: a PluggablePanelMorph(3130) >> submorphs: {a ScrollBar(1013) . a TransformMorph(3047)} >> fullBounds: 36@380 corner: 740@592 >> color: Color white >> extension: a MorphExtension (3891) [other: (layoutFrame -> a LayoutFrame) (vSc...etc... >> borderWidth: 1 >> borderColor: Color lightGray >> model: a Debugger >> slotName: nil >> open: false >> scrollBar: a ScrollBar(1013) >> scroller: a TransformMorph(3047) >> retractableScrollBar: false >> scrollBarOnLeft: false >> getMenuSelector: #codePaneMenu:shifted: >> getMenuTitleSelector: nil >> scrollBarHidden: nil >> hasFocus: false >> hScrollBar: a ScrollBar(2030) >> textMorph: a TextMorphForEditView(3464) >> getTextSelector: #contents >> setTextSelector: #contents:notifying: >> getSelectionSelector: #contentsSelection >> hasUnacceptedEdits: false >> askBeforeDiscardingEdits: true >> selectionInterval: (21 to: 30) >> hasEditingConflicts: false >> getColorSelector: nil >> acceptAction: nil >> unstyledAcceptText: nil >> styler: a SHTextStylerST80 >> >> Debugger(StringHolder)>>perform:orSendTo: >> Receiver: a Debugger >> Arguments and temporary variables: >> selector: #printIt >> otherTarget: a PluggableTextMorphPlus(473) >> Receiver's instance variables: >> dependents: a DependentsArray(a PluggableSystemWindow(1857) a PluggableListMorp...etc... >> contents: a Text for 'test self halt. ^ super test, ''my super call lands on ...etc... >> currentCompiledMethod: nil >> contentsSymbol: #source >> multiWindowState: nil >> interruptedProcess: a Process in Debugger class>>morphicOpenOn:context:label:co...etc... >> interruptedController: nil >> contextStack: an OrderedCollection(MyClass(Object)>>halt MyClass(MyNewAbstracti...etc... >> contextStackIndex: 2 >> contextStackList: an OrderedCollection('MyClass(Object)>>halt' 'MyClass(MyNewAb...etc... >> receiverInspector: an Inspector >> contextVariablesInspector: a ContextVariablesInspector >> externalInterrupt: false >> proceedValue: nil >> selectingPC: true >> savedCursor: ((CursorWithMask >> extent: 16@16 >> depth: 1 >> fromArray: #( >> 2r0 >> 2...etc... >> isolationHead: nil >> failedProject: nil >> errorWasInUIProcess: true >> labelString: nil >> message: nil >> untilExpression: nil >> >> Debugger>>perform:orSendTo: >> Receiver: a Debugger >> Arguments and temporary variables: >> selector: #printIt >> otherTarget: a PluggableTextMorphPlus(473) >> result: nil >> Receiver's instance variables: >> dependents: a DependentsArray(a PluggableSystemWindow(1857) a PluggableListMorp...etc... >> contents: a Text for 'test self halt. ^ super test, ''my super call lands on ...etc... >> currentCompiledMethod: nil >> contentsSymbol: #source >> multiWindowState: nil >> interruptedProcess: a Process in Debugger class>>morphicOpenOn:context:label:co...etc... >> interruptedController: nil >> contextStack: an OrderedCollection(MyClass(Object)>>halt MyClass(MyNewAbstracti...etc... >> contextStackIndex: 2 >> contextStackList: an OrderedCollection('MyClass(Object)>>halt' 'MyClass(MyNewAb...etc... >> receiverInspector: an Inspector >> contextVariablesInspector: a ContextVariablesInspector >> externalInterrupt: false >> proceedValue: nil >> selectingPC: true >> savedCursor: ((CursorWithMask >> extent: 16@16 >> depth: 1 >> fromArray: #( >> 2r0 >> 2...etc... >> isolationHead: nil >> failedProject: nil >> errorWasInUIProcess: true >> labelString: nil >> message: nil >> untilExpression: nil >> >> MenuItemMorph>>DoIt >> Receiver: a MenuItemMorph(77)'print it (p)' >> Arguments and temporary variables: >> >> Receiver's instance variables: >> bounds: 216@558 corner: 359@576 >> owner: a MenuMorph(2209) >> submorphs: #() >> fullBounds: 216@558 corner: 359@576 >> color: Color black >> extension: a MorphExtension (264) [other: (layoutProperties -> a LayoutPropert...etc... >> font: a StrikeFont(Bitmap DejaVu Sans 9 14) >> emphasis: 0 >> contents: 'print it (p)' >> hasFocus: false >> isEnabled: true >> subMenu: nil >> isSelected: false >> target: a Debugger >> selector: #perform:orSendTo: >> arguments: {#printIt . a PluggableTextMorphPlus(473)} >> icon: Form(16x16x32) >> lastMousePosition: nil >> >> CompiledMethod>>valueWithReceiver:arguments: >> Receiver: (MenuItemMorph>>#DoIt "a CompiledMethod(1420)") >> Arguments and temporary variables: >> aReceiver: a MenuItemMorph(77)'print it (p)' >> anArray: #() >> Receiver's instance variables: >> (MenuItemMorph>>#DoIt "a CompiledMethod(1420)") >> >> [] in SmalltalkEditor(TextEditor)>>debug:receiver:in: >> Receiver: a SmalltalkEditor >> Arguments and temporary variables: >> <<error during printing> >> Receiver's instance variables: >> morph: a TextMorphForEditView(4064) >> selectionShowing: false >> model: an ObjectExplorer >> paragraph: a NewParagraph >> markBlock: a CharacterBlock with index 1 and character $s and rectangle 0@0 cor...etc... >> pointBlock: a CharacterBlock with index 62 and rectangle 366@0 corner: 366@16 >> ...etc... >> beginTypeInIndex: nil >> emphasisHere: {a TextFontChange font: 2} >> lastParenLocation: nil >> otherInterval: (61 to: 61) >> oldInterval: (55 to: 54) >> typeAhead: a WriteStream >> styler: nil >> >> [] in BlockClosure>>newProcess >> Receiver: [closure] in SmalltalkEditor(TextEditor)>>debug:receiver:in: >> Arguments and temporary variables: >> >> Receiver's instance variables: >> outerContext: SmalltalkEditor(TextEditor)>>debug:receiver:in: >> startpc: 112 >> numArgs: 0 >> >> >> --- The full stack --- >> Compiler>>evaluateCue:ifFail: >> Compiler>>evaluateCue:ifFail:logged: >> Compiler>>evaluate:in:to:notifying:ifFail:logged: >> [] in SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: >> BlockClosure>>on:do: >> SmalltalkEditor(TextEditor)>>evaluateSelectionAndDo: >> [] in PluggableTextMorphPlus(PluggableTextMorph)>>printIt >> TextMorphForEditView(TextMorph)>>handleEdit: >> PluggableTextMorphPlus(PluggableTextMorph)>>printIt >> Debugger(StringHolder)>>perform:orSendTo: >> Debugger>>perform:orSendTo: >> MenuItemMorph>>DoIt >> CompiledMethod>>valueWithReceiver:arguments: >> [] in SmalltalkEditor(TextEditor)>>debug:receiver:in: >> [] in BlockClosure>>newProcess >> >> >> >> |
Free forum by Nabble | Edit this page |