[squeak-dev] Re: [Vm-dev] About primitive for cleaning compiled method cache

Igor Stasenko siguctua at gmail.com
Thu Mar 14 02:11:11 UTC 2013


On 14 March 2013 00:13, Eliot Miranda <eliot.miranda at gmail.com> wrote:
>
> Hi Nicolas,
>
> On Tue, Mar 12, 2013 at 4:54 AM, Nicolas Cellier <nicolas.cellier.aka.nice at gmail.com> wrote:
>>
>>
>> As I understand it, there is a nuclear weapon
>> - primitive 89 for cleaning all caches
>> and more chirurgical tools:
>> - primitive 116 for cleaning method cache of a single CompiledMethod
>> - primitive 119 for cleaning method cache for all CompiledMethod
>> corresponding to a given selector
>>
>> Currently, when we replace a CompiledMethod in some MethodDictionary,
>> we call both primitive 116 then primitive 119.
>> As I understand it from image code comments, this was to support old
>> VM that would support either one or the other form.
>> Modern VM (interpreter VM4.x serie, Stack or Cog) are mandatory to run
>> a modern image all implement both forms, so backward support argument
>> is gone.
>> I think it's time to clean some dust.
>> So my question is which one is necessary ?
>>
>> Nicolas
>
>
>
>
> Primitive 119.  Primitive 116 will give bugs.  For example, if we have
>
> Object subclass: #A
>
> A subclass: #B
>
> A foo
>     ^#A
>
> A bar
>     ^self foo
>
> and we evaluate
>     B new bar
>

Hmm..

MethodDictionary>>at: key put: value
	"Set the value at key to be value."
	| index |
	index := self findElementOrNil: key.
	(self basicAt: index)
		ifNil:
			[tally := tally + 1.
			self basicAt: index put: key]
		ifNotNil:
			[(array at: index) flushCache].
	array at: index put: value.
	self fullCheck.
	^ value

CM>>flushCache uses primitive 116.
But look at the above implementation:
 it uses flushing only if you replacing existing method.

But not if you adding new method (like overriding in a subclass),
which you can simply expose with following:

Object subclass: #A
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'TTT'

A>>foo
	^ 'foo'

A subclass: #B
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'TTT'

B>>zork
   ^ 'zork '
--
| x y |
x := B new foo.
B methodDict at: #foo put: (B>>#zork).
y := B new foo.
{  x. y }

gives:

 #('foo' 'foo')

while expected answer is
#('foo' 'zork') , of course.

Also gives same result, if i do:

A>>bar
	^self foo

and invoke.
| x y |
x := B new bar.
B methodDict at: #foo put: (B>>#zork).
y := B new bar.
{  x. y }

 #('foo' 'foo')

Apparently, if we consider MethodDictionary>>at:put: as a last line of
defense (against bugs),
that line has a big breach, which needs to be fixed.


> then there is an inline cache entry in A>>#bar and an entry in the first-level method lookup cache that says instances of B receiving #foo should execute A>>#foo.  If we add
>
> B foo
>    ^#B
>
> then we haven't changed A>>#foo but the cache entries in A>>#bar and the first-level method cache for B #foo => A>>#foo must still be flushed.  Make sense?
> --
> best,
> Eliot
>



-- 
Best regards,
Igor Stasenko.


More information about the Squeak-dev mailing list