Problem with Proxies, objects and MethoDict

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

Problem with Proxies, objects and MethoDict

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

Re: Problem with Proxies, objects and MethoDict

Bert Freudenberg
 

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 -


Reply | Threaded
Open this post in threaded view
|

Re: Problem with Proxies, objects and MethoDict

Igor Stasenko
 
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 <[hidden email]> 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.

MessageCatchingProxy.st (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Problem with Proxies, objects and MethoDict

Eliot Miranda-2
In reply to this post by Mariano Martinez Peck
 


On Tue, Sep 28, 2010 at 1:29 PM, Mariano Martinez Peck <[hidden email]> 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


Reply | Threaded
Open this post in threaded view
|

Re: Problem with Proxies, objects and MethoDict

Mariano Martinez Peck
 


On Wed, Sep 29, 2010 at 3:42 AM, Eliot Miranda <[hidden email]> wrote:
 


On Tue, Sep 28, 2010 at 1:29 PM, Mariano Martinez Peck <[hidden email]> 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.

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? 

 
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.


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




Reply | Threaded
Open this post in threaded view
|

Re: Problem with Proxies, objects and MethoDict

Mariano Martinez Peck
 

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


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





Reply | Threaded
Open this post in threaded view
|

Re: Problem with Proxies, objects and MethoDict

Mariano Martinez Peck
 


On Wed, Sep 29, 2010 at 2:25 PM, Mariano Martinez Peck <[hidden email]> 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

 
 
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.


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






Reply | Threaded
Open this post in threaded view
|

Re: Problem with Proxies, objects and MethoDict

Mariano Martinez Peck
In reply to this post by Igor Stasenko
 


On Tue, Sep 28, 2010 at 11:12 PM, Igor Stasenko <[hidden email]> 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 <[hidden email]> 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.


Reply | Threaded
Open this post in threaded view
|

Re: Problem with Proxies, objects and MethoDict

Mariano Martinez Peck
In reply to this post by Igor Stasenko
 


On Tue, Sep 28, 2010 at 11:12 PM, Igor Stasenko <[hidden email]> 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 <[hidden email]> 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.


Reply | Threaded
Open this post in threaded view
|

Re: Problem with Proxies, objects and MethoDict

Igor Stasenko
In reply to this post by Mariano Martinez Peck

On 29 September 2010 16:12, Mariano Martinez Peck <[hidden email]> wrote:

>
>
>
> On Tue, Sep 28, 2010 at 11:12 PM, Igor Stasenko <[hidden email]> 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 <[hidden email]> 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.
>>
>
>
>



--
Best regards,
Igor Stasenko AKA sig.