Hi folks. I am trying to do something and I found a VM crash. Suppose I want to swap out a class, do a become with a proxy (that with the DNU will load the class back). In addition, I have instances of the swapped class.
Example of code (will crash in the last line):
o := MyObject new. o foo: 123. p := ClassProxy new. p become: MyObject. o == nil. o foo.
My Object just extends Object, has an instVar 'foo', and implements the accessors.
ClassProxy implements:
become: aClass className := aClass name. aClass fileOut. super become: aClass
and
doesNotUnderstand: aMessage | reloadedClass | (FileStream fileNamed: className, '.st') fileIn. reloadedClass := Smalltalk at: className. self becomeForward: reloadedClass. ^aMessage sendTo: reloadedClass
So....does someone know why the crash?
how can I solve it ?
Thanks in advance
Mariano
On 28.09.2010, at 22:29, Mariano Martinez Peck wrote:
Hi folks. I am trying to do something and I found a VM crash. Suppose I want to swap out a class, do a become with a proxy (that with the DNU will load the class back). In addition, I have instances of the swapped class.
Example of code (will crash in the last line):
o := MyObject new. o foo: 123. p := ClassProxy new. p become: MyObject. o == nil. o foo.
My Object just extends Object, has an instVar 'foo', and implements the accessors.
ClassProxy implements:
become: aClass className := aClass name. aClass fileOut. super become: aClass
and
doesNotUnderstand: aMessage | reloadedClass | (FileStream fileNamed: className, '.st') fileIn. reloadedClass := Smalltalk at: className. self becomeForward: reloadedClass. ^aMessage sendTo: reloadedClass
So....does someone know why the crash?
Looks like o's class pointer does not point to a class after the become. When the VM tries to lookup #foo in o's class it crashes.
how can I solve it ?
I'd say you cannot get rid of a class if there are still instances of it. You can stub out the class however. If the method dict is nil, the VM will send cannotInterpret: if you send a message to an instance. You should be able to use that instead of #doesNotUnderstand:.
- Bert -
Here it is. Just be aware, that its not intercepting all messages. Some messages like #== or #class is early bound by compiler/VM, so even if you redefine them, their behavior won't be changed.
(I forgot where to get the list of these exceptional selectors). Smalltalk specialSelectors seems like not the same thing.
On 28 September 2010 23:48, Bert Freudenberg bert@freudenbergs.de wrote:
On 28.09.2010, at 22:29, Mariano Martinez Peck wrote:
Hi folks. I am trying to do something and I found a VM crash. Suppose I want to swap out a class, do a become with a proxy (that with the DNU will load the class back). In addition, I have instances of the swapped class.
Example of code (will crash in the last line):
o := MyObject new. o foo: 123. p := ClassProxy new. p become: MyObject. o == nil. o foo.
My Object just extends Object, has an instVar 'foo', and implements the accessors.
ClassProxy implements:
become: aClass className := aClass name. aClass fileOut. super become: aClass
and
doesNotUnderstand: aMessage | reloadedClass | (FileStream fileNamed: className, '.st') fileIn. reloadedClass := Smalltalk at: className. self becomeForward: reloadedClass. ^aMessage sendTo: reloadedClass
So....does someone know why the crash?
Looks like o's class pointer does not point to a class after the become. When the VM tries to lookup #foo in o's class it crashes.
how can I solve it ?
I'd say you cannot get rid of a class if there are still instances of it. You can stub out the class however. If the method dict is nil, the VM will send cannotInterpret: if you send a message to an instance. You should be able to use that instead of #doesNotUnderstand:.
- Bert -
On Tue, Sep 28, 2010 at 11:12 PM, Igor Stasenko siguctua@gmail.com wrote:
Here it is. Just be aware, that its not intercepting all messages. Some messages like #== or #class is early bound by compiler/VM, so even if you redefine them, their behavior won't be changed.
Thanks Igor. I am trying to understand your code. Now...how I should use MessageCatchingProxy ?
how can I adapt this code to use your proxy?
| o p | o := MyClass new. o foo: 123. p := ClassProxy3 new. p become: MyClass. MyClass flushCache. ClassProxy3 flushCache. o == nil. Transcript show: o class name; cr. o foo.
thanks a lot
mariano
(I forgot where to get the list of these exceptional selectors). Smalltalk specialSelectors seems like not the same thing.
On 28 September 2010 23:48, Bert Freudenberg bert@freudenbergs.de wrote:
On 28.09.2010, at 22:29, Mariano Martinez Peck wrote:
Hi folks. I am trying to do something and I found a VM crash. Suppose I
want to swap out a class, do a become with a proxy (that with the DNU will load the class back). In addition, I have instances of the swapped class.
Example of code (will crash in the last line):
o := MyObject new. o foo: 123. p := ClassProxy new. p become: MyObject. o == nil. o foo.
My Object just extends Object, has an instVar 'foo', and implements the
accessors.
ClassProxy implements:
become: aClass className := aClass name. aClass fileOut. super become: aClass
and
doesNotUnderstand: aMessage | reloadedClass | (FileStream fileNamed: className, '.st') fileIn. reloadedClass := Smalltalk at: className. self becomeForward: reloadedClass. ^aMessage sendTo: reloadedClass
So....does someone know why the crash?
Looks like o's class pointer does not point to a class after the become.
When the VM tries to lookup #foo in o's class it crashes.
how can I solve it ?
I'd say you cannot get rid of a class if there are still instances of it.
You can stub out the class however. If the method dict is nil, the VM will send cannotInterpret: if you send a message to an instance. You should be able to use that instead of #doesNotUnderstand:.
- Bert -
-- Best regards, Igor Stasenko AKA sig.
On 29 September 2010 16:12, Mariano Martinez Peck marianopeck@gmail.com wrote:
On Tue, Sep 28, 2010 at 11:12 PM, Igor Stasenko siguctua@gmail.com wrote:
Here it is. Just be aware, that its not intercepting all messages. Some messages like #== or #class is early bound by compiler/VM, so even if you redefine them, their behavior won't be changed.
Thanks Igor. I am trying to understand your code. Now...how I should use MessageCatchingProxy ?
how can I adapt this code to use your proxy?
Just subclass it, and override #handleMessage: forProxy: where you can send a message to other object or do something else.
Then you can wrap some object with it:
wrapped := MyProxy wrap: myclass.
| o p | o := MyClass new. o foo: 123. p := ClassProxy3 new. p become: MyClass. MyClass flushCache. ClassProxy3 flushCache. o == nil. Transcript show: o class name; cr. o foo.
thanks a lot
mariano
(I forgot where to get the list of these exceptional selectors). Smalltalk specialSelectors seems like not the same thing.
On 28 September 2010 23:48, Bert Freudenberg bert@freudenbergs.de wrote:
On 28.09.2010, at 22:29, Mariano Martinez Peck wrote:
Hi folks. I am trying to do something and I found a VM crash. Suppose I want to swap out a class, do a become with a proxy (that with the DNU will load the class back). In addition, I have instances of the swapped class.
Example of code (will crash in the last line):
o := MyObject new. o foo: 123. p := ClassProxy new. p become: MyObject. o == nil. o foo.
My Object just extends Object, has an instVar 'foo', and implements the accessors.
ClassProxy implements:
become: aClass className := aClass name. aClass fileOut. super become: aClass
and
doesNotUnderstand: aMessage | reloadedClass | (FileStream fileNamed: className, '.st') fileIn. reloadedClass := Smalltalk at: className. self becomeForward: reloadedClass. ^aMessage sendTo: reloadedClass
So....does someone know why the crash?
Looks like o's class pointer does not point to a class after the become. When the VM tries to lookup #foo in o's class it crashes.
how can I solve it ?
I'd say you cannot get rid of a class if there are still instances of it. You can stub out the class however. If the method dict is nil, the VM will send cannotInterpret: if you send a message to an instance. You should be able to use that instead of #doesNotUnderstand:.
- Bert -
-- Best regards, Igor Stasenko AKA sig.
On Tue, Sep 28, 2010 at 11:12 PM, Igor Stasenko siguctua@gmail.com wrote:
Here it is. Just be aware, that its not intercepting all messages. Some messages like #== or #class is early bound by compiler/VM, so even if you redefine them, their behavior won't be changed.
Thanks Igor. I am trying to understand your code. Now...how I should use MessageCatchingProxy ?
how can I adapt this code to use your proxy?
| o p | o := MyClass new. o foo: 123. p := ClassProxy3 new. MessageCatchingProxy wrap_ p become: MyClass. MyClass flushCache. ClassProxy3 flushCache. o == nil. Transcript show: o class name; cr. o foo.
(I forgot where to get the list of these exceptional selectors). Smalltalk specialSelectors seems like not the same thing.
I would love to know this as well.
Thanks
Mariano
On 28 September 2010 23:48, Bert Freudenberg bert@freudenbergs.de wrote:
On 28.09.2010, at 22:29, Mariano Martinez Peck wrote:
Hi folks. I am trying to do something and I found a VM crash. Suppose I
want to swap out a class, do a become with a proxy (that with the DNU will load the class back). In addition, I have instances of the swapped class.
Example of code (will crash in the last line):
o := MyObject new. o foo: 123. p := ClassProxy new. p become: MyObject. o == nil. o foo.
My Object just extends Object, has an instVar 'foo', and implements the
accessors.
ClassProxy implements:
become: aClass className := aClass name. aClass fileOut. super become: aClass
and
doesNotUnderstand: aMessage | reloadedClass | (FileStream fileNamed: className, '.st') fileIn. reloadedClass := Smalltalk at: className. self becomeForward: reloadedClass. ^aMessage sendTo: reloadedClass
So....does someone know why the crash?
Looks like o's class pointer does not point to a class after the become.
When the VM tries to lookup #foo in o's class it crashes.
how can I solve it ?
I'd say you cannot get rid of a class if there are still instances of it.
You can stub out the class however. If the method dict is nil, the VM will send cannotInterpret: if you send a message to an instance. You should be able to use that instead of #doesNotUnderstand:.
- Bert -
-- Best regards, Igor Stasenko AKA sig.
On Tue, Sep 28, 2010 at 1:29 PM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
Hi folks. I am trying to do something and I found a VM crash. Suppose I want to swap out a class, do a become with a proxy (that with the DNU will load the class back). In addition, I have instances of the swapped class.
Example of code (will crash in the last line):
o := MyObject new. o foo: 123. p := ClassProxy new. p become: MyObject. o == nil. o foo.
My Object just extends Object, has an instVar 'foo', and implements the accessors.
ClassProxy implements:
become: aClass className := aClass name. aClass fileOut. super become: aClass
and
doesNotUnderstand: aMessage | reloadedClass | (FileStream fileNamed: className, '.st') fileIn. reloadedClass := Smalltalk at: className. self becomeForward: reloadedClass. ^aMessage sendTo: reloadedClass
So....does someone know why the crash?
I'm not sure but here are some possible reasons...
1. you didn't flush the method lookup cache after doing the becomeForward: and the perform in sentTo: found a stale method and boom. 2. you became from a class with N inst vars to one with N+M inst vars and the methods of the new class accessed inst vars > N which are off the end of your instance, causing the VM to read invalid oops and boom.
So a) always flush the method lookup cache and b) /never/ cause the VM to read past an object by changing the class underneath an object such that the class accesses more inst vars than the instance has.
how can I solve it ?
Thanks in advance
Mariano
On Wed, Sep 29, 2010 at 3:42 AM, Eliot Miranda eliot.miranda@gmail.comwrote:
On Tue, Sep 28, 2010 at 1:29 PM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
Hi folks. I am trying to do something and I found a VM crash. Suppose I want to swap out a class, do a become with a proxy (that with the DNU will load the class back). In addition, I have instances of the swapped class.
Example of code (will crash in the last line):
o := MyObject new. o foo: 123. p := ClassProxy new. p become: MyObject. o == nil. o foo.
My Object just extends Object, has an instVar 'foo', and implements the accessors.
ClassProxy implements:
become: aClass className := aClass name. aClass fileOut. super become: aClass
and
doesNotUnderstand: aMessage | reloadedClass | (FileStream fileNamed: className, '.st') fileIn. reloadedClass := Smalltalk at: className. self becomeForward: reloadedClass. ^aMessage sendTo: reloadedClass
So....does someone know why the crash?
I'm not sure but here are some possible reasons...
- you didn't flush the method lookup cache after doing the becomeForward:
and the perform in sentTo: found a stale method and boom.
Thanks Eliot. I was checking the code of the become in #primitiveArrayBecome and it seems that in #mapPointersInObjectsFrom: self startOfMemory to: they do the "self flushMethodCacheFrom: memStart to: memEnd."
Anyway, I tried it with
| o p | o := MyClass new. o foo: 123. p := ClassProxy new. p become: MyClass. MyClass flushCache. ClassProxy flushCache. o == nil. Transcript show: o class name; cr. o foo.
but same results.
Now, something interesting is that "Transcript show: o class name; cr." prints "MyClass". Is this correct?
- you became from a class with N inst vars to one with N+M inst vars and
the methods of the new class accessed inst vars > N which are off the end of your instance, causing the VM to read invalid oops and boom.
My case is even more complicated. I want to become from a CLASS to an INSTANCE. I mean, I want to become the class MyClass with AN INSTANCE of PROXY CLASS. Then the proxy class uses te DNU to bring the other back.
Now I was thinking that maybe the proxy class should not extend from ProtoObject but from Behavior or similar? But I want smaller objects...I don't want to spend instances in "uperclass methodDict format'" since the only thing I have to do is with DNU bring back other object.
Finally, I have a question. I tried to look at the #become but I didn't get it... When I do a become from a class to an object for example, if there were (normal) pointers (slots in other objects) to that class, then they are updated and point to the other object. However, what happens with the instances of that class? is the class pointer in their object header consider like a normal pointer? are those piointers updated also by the #become? Maybe they are not and this is why "Transcript show: o class name; cr." prints "MyClass" ?
Sorry for the newbie question...I am learning all this...
Cheers
Mariano
So a) always flush the method lookup cache and b) /never/ cause the VM to read past an object by changing the class underneath an object such that the class accesses more inst vars than the instance has.
how can I solve it ?
Thanks in advance
Mariano
Anyway, I tried it with
| o p | o := MyClass new.
o foo: 123. p := ClassProxy new. p become: MyClass. MyClass flushCache. ClassProxy flushCache. o == nil. Transcript show: o class name; cr. o foo.
but same results.
Now, something interesting is that "Transcript show: o class name; cr." prints "MyClass". Is this correct?
Grrrrr no, sorry, that's not true...can you believe there was a " Transcript cr; show: self name. " in the fileout code ? heheheh
Now I changed the proxy to extends Class (to see if it works) and at least it doesn't crash.
"Transcript show: o class name; cr. " prints "a subclass of Object" and after the evaluation of the code, I get the error:
MessageNotUnderstood: a subclass of Object>>foo
mmmmm
I will continue investigating....
- you became from a class with N inst vars to one with N+M inst vars and
the methods of the new class accessed inst vars > N which are off the end of your instance, causing the VM to read invalid oops and boom.
My case is even more complicated. I want to become from a CLASS to an INSTANCE. I mean, I want to become the class MyClass with AN INSTANCE of PROXY CLASS. Then the proxy class uses te DNU to bring the other back.
Now I was thinking that maybe the proxy class should not extend from ProtoObject but from Behavior or similar? But I want smaller objects...I don't want to spend instances in "uperclass methodDict format'" since the only thing I have to do is with DNU bring back other object.
Finally, I have a question. I tried to look at the #become but I didn't get it... When I do a become from a class to an object for example, if there were (normal) pointers (slots in other objects) to that class, then they are updated and point to the other object. However, what happens with the instances of that class? is the class pointer in their object header consider like a normal pointer? are those piointers updated also by the #become? Maybe they are not and this is why "Transcript show: o class name; cr." prints "MyClass" ?
Sorry for the newbie question...I am learning all this...
Cheers
Mariano
So a) always flush the method lookup cache and b) /never/ cause the VM to read past an object by changing the class underneath an object such that the class accesses more inst vars than the instance has.
how can I solve it ?
Thanks in advance
Mariano
On Wed, Sep 29, 2010 at 2:25 PM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
Anyway, I tried it with
| o p | o := MyClass new.
o foo: 123. p := ClassProxy new. p become: MyClass. MyClass flushCache. ClassProxy flushCache. o == nil. Transcript show: o class name; cr. o foo.
but same results.
Now, something interesting is that "Transcript show: o class name; cr." prints "MyClass". Is this correct?
Grrrrr no, sorry, that's not true...can you believe there was a " Transcript cr; show: self name. " in the fileout code ? heheheh
Now I changed the proxy to extends Class (to see if it works) and at least it doesn't crash.
"Transcript show: o class name; cr. " prints "a subclass of Object" and after the evaluation of the code, I get the error:
MessageNotUnderstood: a subclass of Object>>foo
mmmmm
I will continue investigating....
Something interesting is that after evaluating that code, and recieving the error, MyClass which was:
Object subclass: #MyClass instanceVariableNames: 'foo' classVariableNames: '' poolDictionaries: '' category: 'Proxies'
now it is:
Object subclass: 'a subclass of Object' instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'nil'
weird....
thanks!
mariano
- you became from a class with N inst vars to one with N+M inst vars and
the methods of the new class accessed inst vars > N which are off the end of your instance, causing the VM to read invalid oops and boom.
My case is even more complicated. I want to become from a CLASS to an INSTANCE. I mean, I want to become the class MyClass with AN INSTANCE of PROXY CLASS. Then the proxy class uses te DNU to bring the other back.
Now I was thinking that maybe the proxy class should not extend from ProtoObject but from Behavior or similar? But I want smaller objects...I don't want to spend instances in "uperclass methodDict format'" since the only thing I have to do is with DNU bring back other object.
Finally, I have a question. I tried to look at the #become but I didn't get it... When I do a become from a class to an object for example, if there were (normal) pointers (slots in other objects) to that class, then they are updated and point to the other object. However, what happens with the instances of that class? is the class pointer in their object header consider like a normal pointer? are those piointers updated also by the #become? Maybe they are not and this is why "Transcript show: o class name; cr." prints "MyClass" ?
Sorry for the newbie question...I am learning all this...
Cheers
Mariano
So a) always flush the method lookup cache and b) /never/ cause the VM to read past an object by changing the class underneath an object such that the class accesses more inst vars than the instance has.
how can I solve it ?
Thanks in advance
Mariano
vm-dev@lists.squeakfoundation.org