How does the VM deal with method dictionaries?

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

How does the VM deal with method dictionaries?

Christoph Thiede

Hi all,


one curious question:


c := Object newSubclass.
c compile: 'foo ^#foo'.
c methodDict: (ObjectTracer on: c methodDict).
c flushCache.
o := c new.
o foo.


I would have expected to get a notification from the ObjectTracer when executing the last line, because somehow the execution machinery must resolve the method to be executed. But actually, what I get is an MNU (Object1 >> #foo).

For comparison: If I skip the ObjectTracer line, the example works and #foo is returned.

Can anyone explain this? :-)


Best,

Christoph



Carpe Squeak!
Reply | Threaded
Open this post in threaded view
|

Re: How does the VM deal with method dictionaries?

Bert Freudenberg
On Mon, Feb 24, 2020 at 5:14 AM Thiede, Christoph <[hidden email]> wrote:

Hi all,


one curious question:


c := Object newSubclass.
c compile: 'foo ^#foo'.
c methodDict: (ObjectTracer on: c methodDict).
c flushCache.
o := c new.
o foo.


I would have expected to get a notification from the ObjectTracer when executing the last line, because somehow the execution machinery must resolve the method to be executed. But actually, what I get is an MNU (Object1 >> #foo).

For comparison: If I skip the ObjectTracer line, the example works and #foo is returned.

The VM assumes the object in the methodDict slot of a class is a MethodDictionary. It will look for a method with the #foo selector, and if it does not find that, it will invoke #doesNotUnderstand instead.

There is only one special value the VM recognizes instead, and that is nil. If a nil methodDict is encountered, the VM will send #cannotInterpret:.

This lets the image intercept the VM's method lookup. The default handler for cannotInterpret: invokes the class's #lookupSelector: method and retries the message send if found.

This was used for example to swap out classes to disk when memory was still expensive. The class is replaced (via become:) by a stub that has a nil in the slot that normally is the method dict. So when a message is sent to an instance of a swapped-out class, the cannotInterpret: mechanism loads the actual class from disc, replaces the stub, and then continues execution as if nothing ever happened.

I find looking at the SqueakJS sources quite instructive, since they are not obscured by all the optimizations in the OpenSmalltalk VM. Here's the relevant part, findSelectorInClass() which is invoked from send()

Have fun!
- Bert -


Reply | Threaded
Open this post in threaded view
|

Re: How does the VM deal with method dictionaries?

Christoph Thiede

Hi Bert,


thanks for the helpful answer. So there is no chance to use a first-class object for the method dictionary - unless I set the instance variable methodDictionary to nil and force the VM to send #cannotInterpret: for every message? :-)


Your SqueakJS sources are indeed very helpful for studying a VM implementation. Great work!

Best,
Christoph

Von: Squeak-dev <[hidden email]> im Auftrag von Bert Freudenberg <[hidden email]>
Gesendet: Montag, 24. Februar 2020 23:21:44
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] How does the VM deal with method dictionaries?
 
On Mon, Feb 24, 2020 at 5:14 AM Thiede, Christoph <[hidden email]> wrote:

Hi all,


one curious question:


c := Object newSubclass.
c compile: 'foo ^#foo'.
c methodDict: (ObjectTracer on: c methodDict).
c flushCache.
o := c new.
o foo.


I would have expected to get a notification from the ObjectTracer when executing the last line, because somehow the execution machinery must resolve the method to be executed. But actually, what I get is an MNU (Object1 >> #foo).

For comparison: If I skip the ObjectTracer line, the example works and #foo is returned.

The VM assumes the object in the methodDict slot of a class is a MethodDictionary. It will look for a method with the #foo selector, and if it does not find that, it will invoke #doesNotUnderstand instead.

There is only one special value the VM recognizes instead, and that is nil. If a nil methodDict is encountered, the VM will send #cannotInterpret:.

This lets the image intercept the VM's method lookup. The default handler for cannotInterpret: invokes the class's #lookupSelector: method and retries the message send if found.

This was used for example to swap out classes to disk when memory was still expensive. The class is replaced (via become:) by a stub that has a nil in the slot that normally is the method dict. So when a message is sent to an instance of a swapped-out class, the cannotInterpret: mechanism loads the actual class from disc, replaces the stub, and then continues execution as if nothing ever happened.

I find looking at the SqueakJS sources quite instructive, since they are not obscured by all the optimizations in the OpenSmalltalk VM. Here's the relevant part, findSelectorInClass() which is invoked from send()

Have fun!
- Bert -


Carpe Squeak!