renaming a class causes invalid super pointer CompiledMethod..!

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|

renaming a class causes invalid super pointer CompiledMethod..!

Chris Muller-4
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..

Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Tobias Pape
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



Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Chris Muller-3
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
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Eliot Miranda-2
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
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!

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


Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Eliot Miranda-2


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


Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Tobias Pape

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:.




Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Eliot Miranda-2
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:


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


Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Tobias Pape

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.


Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Tobias Pape
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?






Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Bert Freudenberg
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
Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Chris Muller-3
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
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Nicolas Cellier


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
>
>
>




Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Chris Muller-3
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
>> >
>> >
>> >
>>
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Bert Freudenberg
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
Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Chris Muller-3
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
>> >
>> >
>> >
>>
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Tobias Pape
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.

 
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
Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

timrowledge
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.



Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Eliot Miranda-2
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

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.


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.

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.
 

@Bert, Eliot: Which one do you think would be correct? the Stack is down below[1].

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
        -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







--
best,
Eliot


Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Chris Muller-3
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
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: renaming a class causes invalid super pointer CompiledMethod..!

Chris Muller-3
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
>>
>>
>>
>>