<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2015-01-20 23:56 GMT+01:00 Chris Muller <span dir="ltr">&lt;<a href="mailto:asqueaker@gmail.com" target="_blank">asqueaker@gmail.com</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Eliot, there were TWO problems, Bert and Tobias have fixed one of<br>
them.  The second one is still unfixed in trunk.  When you run this<br>
script and arrive at the debugger, step INTO:<br>
<br>
Object compile: &#39;test  ^&#39;&#39;Hello from Object&#39;&#39;&#39;.<br>
(Object subclass: #MyClass instanceVariableNames: &#39;&#39;<br>
classVariableNames: &#39;&#39; poolDictionaries: &#39;&#39; category: &#39;Test&#39;) compile:<br>
&#39;test  ^ super halt test, &#39;&#39;my super call lands on itself!&#39;&#39;&#39;.<br>
(Smalltalk classNamed: #MyClass) rename: &#39;MyNewAbstraction&#39;.<br>
(Smalltalk classNamed: #MyNewAbstraction) new test<br>
<br></blockquote><div><br></div><div>But it behaves as it should...<br></div><div>You first send halt to super.<br></div><div>If you resume it just answer self.<br><br></div><div>Then you send test to self (it&#39;s not a super send and never been)<br><br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
then be sure to step INTO the super call to #test.  See how it lands<br>
you in teh same method?  THAT bug exists back at least as far back as<br>
4.2, so I don&#39;t think its Environments related.<br>
<br>
I took a look at it and presented my findings in the other email<br>
thread with subject &quot;The Inbox: Environments-cmm.52.mcz&quot;, -- that<br>
screenshot showing that the bytecodes are teh same and the literal<br>
binding looks correct.<br>
<br>
So I have no idea why its not calling super correctly...<br>
<br>
<br>
On Tue, Jan 20, 2015 at 2:38 PM, Eliot Miranda &lt;<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>&gt; wrote:<br>
&gt;<br>
&gt; Ugh, I&#39;m behind the times, Tobias you&#39;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&#39;t you think that that code belongs in the BindingPolicy?<br>
&gt;<br>
&gt; On Tue, Jan 20, 2015 at 12:33 PM, Eliot Miranda &lt;<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; On Tue, Jan 20, 2015 at 12:26 PM, Eliot Miranda &lt;<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>&gt; wrote:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Hi Chris, Hi Colin,<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; On Thu, Jan 15, 2015 at 2:48 PM, Chris Muller &lt;<a href="mailto:ma.chris.m@gmail.com">ma.chris.m@gmail.com</a>&gt; wrote:<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I did a minor class-hierarchy refactoring today which resulted in a an<br>
&gt;&gt;&gt;&gt; invalid super pointer, resulting in a confusing image lock up due to<br>
&gt;&gt;&gt;&gt; tight recursion.  The script, below, demonstrates the issue in trunk:<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Object compile: &#39;test  ^&#39;&#39;Hello from Object&#39;&#39;&#39;.<br>
&gt;&gt;&gt;&gt; (Object subclass: #MyClass instanceVariableNames: &#39;&#39;<br>
&gt;&gt;&gt;&gt; classVariableNames: &#39;&#39; poolDictionaries: &#39;&#39; category: &#39;Test&#39;) compile:<br>
&gt;&gt;&gt;&gt; &#39;test  ^ super halt test, &#39;&#39;my super call lands on myself!&#39;&#39;&#39;.<br>
&gt;&gt;&gt;&gt; (Smalltalk classNamed: #MyClass) rename: &#39;MyNewAbstraction&#39;.<br>
&gt;&gt;&gt;&gt; ((Smalltalk classNamed: #MyNewAbstraction) subclass: #MyClass<br>
&gt;&gt;&gt;&gt; instanceVariableNames: &#39;&#39; classVariableNames: &#39;&#39; poolDictionaries: &#39;&#39;<br>
&gt;&gt;&gt;&gt; category: &#39;Test&#39;).<br>
&gt;&gt;&gt;&gt; (Smalltalk classNamed: #MyNewAbstraction) new test<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; But an existing method in the original MyClass had a call to super<br>
&gt;&gt;&gt;&gt; which now lands in itself, resulting in a tight recursion.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; The same script without creating the new subclass results in an<br>
&gt;&gt;&gt;&gt; instant VM crash (both interpreter 2357 and cog 3205):<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Object compile: &#39;test  ^&#39;&#39;Hello from Object&#39;&#39;&#39;.<br>
&gt;&gt;&gt;&gt; (Object subclass: #MyClass instanceVariableNames: &#39;&#39;<br>
&gt;&gt;&gt;&gt; classVariableNames: &#39;&#39; poolDictionaries: &#39;&#39; category: &#39;Test&#39;) compile:<br>
&gt;&gt;&gt;&gt; &#39;test  ^ super halt test, &#39;&#39;my super call lands on itself!&#39;&#39;&#39;.<br>
&gt;&gt;&gt;&gt; (Smalltalk classNamed: #MyClass) rename: &#39;MyNewAbstraction&#39;.<br>
&gt;&gt;&gt;&gt; (Smalltalk classNamed: #MyNewAbstraction) new test<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I even tried recompiling my entire class hierarchy which was renamed,<br>
&gt;&gt;&gt;&gt; but it didn&#39;t help.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; How can this be?  I _KNOW_ I&#39;ve used rename class many times in the<br>
&gt;&gt;&gt;&gt; past...  A regression?<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; This is indeed an Environments regression.  The issue is where to fix the problem.  One way to look at it is that Environment&gt;&gt;renameClass:from:to: does not update bindings in the renamed class&#39;s methods.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Here&#39;s what the old code did:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; SystemDictionary&gt;&gt;renameClass: aClass from: oldName to: newName<br>
&gt;&gt;&gt; &quot;Rename the class, aClass, to have the title newName.&quot;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; | oldref category |<br>
&gt;&gt;&gt; category := SystemOrganization categoryOfElement: oldName.<br>
&gt;&gt;&gt; self organization classify: newName under: category suppressIfDefault: true.<br>
&gt;&gt;&gt; self organization removeElement: oldName.<br>
&gt;&gt;&gt; oldref := self associationAt: oldName.<br>
&gt;&gt;&gt; self removeKey: oldName.<br>
&gt;&gt;&gt; ** oldref key: newName.<br>
&gt;&gt;&gt; self add: oldref.  &quot;Old association preserves old refs&quot;<br>
&gt;&gt;&gt; Smalltalk renamedClass: aClass from: oldName to: newName.<br>
&gt;&gt;&gt; self flushClassNameCache.<br>
&gt;&gt;&gt; SystemChangeNotifier uniqueInstance classRenamed: aClass from: oldName to: newName inCategory: category<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; The starred line changes the key on the old class&#39;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).<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; The new code simply forgets to do this:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Environment&gt;&gt;renameClass: aClass from: oldName to: newName<br>
&gt;&gt;&gt; &quot;Rename the class, aClass, to have the title newName.&quot;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; | binding category |<br>
&gt;&gt;&gt; category := self organization categoryOfElement: oldName.<br>
&gt;&gt;&gt; self organization classify: newName under: category suppressIfDefault: true.<br>
&gt;&gt;&gt; self organization removeElement: oldName.<br>
&gt;&gt;&gt; binding := self declarationOf: oldName.<br>
&gt;&gt;&gt; declarations removeKey: oldName.<br>
&gt;&gt;&gt; self binding: binding removedFrom: self.<br>
&gt;&gt;&gt; binding := newName =&gt; aClass.<br>
&gt;&gt;&gt; declarations add: binding.<br>
&gt;&gt;&gt; self binding: binding addedTo: self.<br>
&gt;&gt;&gt; Smalltalk renamedClass: aClass from: oldName to: newName.<br>
&gt;&gt;&gt; SystemChangeNotifier uniqueInstance<br>
&gt;&gt;&gt; classRenamed: aClass<br>
&gt;&gt;&gt; from: oldName<br>
&gt;&gt;&gt; to: newName<br>
&gt;&gt;&gt; inCategory: category<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; But should the change go in Environment&gt;&gt;renameClass:from:to: or in the BindingPolicy?  i.e. it could be implemented either in Environment&gt;&gt;renameClass:from:to:, or in Environment&gt;&gt;showBinding:.  I guess the former, but I&#39;m cc&#39;ing Colin, because know it?, he wrote it!<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; and if the fix should indeed go in Environment&gt;&gt;renameClass:from:to: , it is as simple as<br>
&gt;&gt;<br>
&gt;&gt; Environment&gt;&gt;renameClass: aClass from: oldName to: newName<br>
&gt;&gt; &quot;Rename the class, aClass, to have the title newName.&quot;<br>
&gt;&gt;<br>
&gt;&gt; | binding category |<br>
&gt;&gt; category := self organization categoryOfElement: oldName.<br>
&gt;&gt; self organization classify: newName under: category suppressIfDefault: true.<br>
&gt;&gt; self organization removeElement: oldName.<br>
&gt;&gt; binding := self declarationOf: oldName.<br>
&gt;&gt; declarations removeKey: oldName.<br>
&gt;&gt; self binding: binding removedFrom: self.<br>
&gt;&gt; binding := newName =&gt; aClass.<br>
&gt;&gt; declarations add: binding.<br>
&gt;&gt; self binding: binding addedTo: self.<br>
&gt;&gt;<br>
&gt;&gt; ** aClass updateMethodBindingsTo: binding.<br>
&gt;&gt; Smalltalk renamedClass: aClass from: oldName to: newName.<br>
&gt;&gt; SystemChangeNotifier uniqueInstance<br>
&gt;&gt; classRenamed: aClass<br>
&gt;&gt; from: oldName<br>
&gt;&gt; to: newName<br>
&gt;&gt; inCategory: category<br>
&gt;&gt;<br>
&gt;&gt; I&#39;ll make this change and we can alter later if Colin thinks it&#39;s in the wrong place.<br>
&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; In any case there needs to be a test that checks that a method&#39;s methodClassAssociation is correctly updated after a rename.  I bet Colin would have not made this slip had there been a test.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Here&#39;s the code I used to test this:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; | mca1 mca2 |<br>
&gt;&gt;&gt; Object compile: &#39;test  ^&#39;&#39;Hello from Object&#39;&#39;&#39;.<br>
&gt;&gt;&gt; (Object<br>
&gt;&gt;&gt; subclass: #MyClass instanceVariableNames: &#39;&#39;<br>
&gt;&gt;&gt; classVariableNames: &#39;&#39;<br>
&gt;&gt;&gt; poolDictionaries: &#39;&#39;<br>
&gt;&gt;&gt; category: &#39;Test&#39;)<br>
&gt;&gt;&gt; compile: &#39;test  ^ super halt test, &#39;&#39;my super call lands on itself!&#39;&#39;&#39;.<br>
&gt;&gt;&gt; mca1 := ((Smalltalk classNamed: #MyClass)&gt;&gt;#test) methodClassAssociation.<br>
&gt;&gt;&gt; (Smalltalk classNamed: #MyClass)<br>
&gt;&gt;&gt; rename: &#39;MyNewAbstraction&#39;.<br>
&gt;&gt;&gt; mca2 := ((Smalltalk classNamed: #MyNewAbstraction)&gt;&gt;#test) methodClassAssociation.<br>
&gt;&gt;&gt; { mca1. mca2. mca1 == mca2. mca1 == (Smalltalk bindingOf: #MyNewAbstraction). mca2 == (Smalltalk bindingOf: #MyNewAbstraction)}<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; It answers { #MyClass=&gt;nil . #MyClass=&gt;nil . true . false . false}<br>
&gt;&gt;&gt; i.e. the binding isn&#39;t updated, but changes from #MyClass=&gt;MyClass to #MyClass=&gt;nil in binding:removedFrom:.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; --<br>
&gt;&gt;&gt; HTH,<br>
&gt;&gt;&gt; Eliot<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
<span class="HOEnZb"><font color="#888888">&gt;&gt;<br>
&gt;&gt; --<br>
&gt;&gt; best,<br>
&gt;&gt; Eliot<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt; --<br>
&gt; best,<br>
&gt; Eliot<br>
&gt;<br>
&gt;<br>
&gt;<br>
<br>
</font></span></blockquote></div><br></div></div>