[squeak-dev] Re: Using #= for integer comparison instead of #==
leves at elte.hu
Wed Nov 17 05:52:03 UTC 2010
On Tue, 16 Nov 2010, Andreas Raab wrote:
> On 11/16/2010 8:05 PM, Levente Uzonyi wrote:
>> I wasn't clear when I said atomic code. I expected #= (and #<, #>, etc)
>> to _not_ be a real message send when both the receiver and the argument
>> are SmallIntegers. Otherwise what's the point of having separate
>> bytecodes for them?
> Space. It makes a big difference for the most common selectors (#at:,
> #at:put:, #size, #+ etc) to be be encoded as bytecodes. It avoids having to
> allocate a literal every time you see the selector. Often, the special
I just evaluated this:
| count specialSelectors |
count := 0.
specialSelectors := Smalltalk specialSelectors select: [ :each | each isSymbol ].
CompiledMethod allInstancesDo: [ :method |
| messages |
messages := method messages.
count := count + (specialSelectors count: [ :selector |
messages includes: selector ]) ].
The result is 50947 for a slightly modified Trunk image. This means
that this technique saves less than 200kB (assuming 32-bit slots in the
literal frame), but it uses 32 bytecodes.
200 kB is not much compared to the size of the image (about 1-2%).
Also the 32 most frequently used methods are not the 32 special selectors.
| b mostFrequentSelectors specialSelectors |
b := Bag new.
CompiledMethod allInstancesDo: [ :method | b addAll: method messages ].
mostFrequentSelectors := (b sortedCounts first: 32) replace: #value.
specialSelectors := Smalltalk specialSelectors select: #isSymbol.
specialSelectors difference: mostFrequentSelectors. "Shouldn't be special"
mostFrequentSelectors difference: specialSelectors. "Should be special"
#(#'>=' #'~=' #/ #'\\' #bitShift: #'//' #bitAnd: #bitOr: #next #atEnd #blockCopy: #value #value: #x #y)
#(#, #assert: #first #name #add: #nextPutAll: #isEmpty #error: #asString #includes: #default #translated #not #on: #collect:))
Another 40kB could be saved by changing these.
Btw, there's a "free" bytecode: 200 - #blockCopy:.
> selector bytecodes look like this:
> messageSelector := self specialSelector: 20.
> argumentCount := 1.
> self normalSend.
> I.e., it just dispatches to normalSend where the regular lookup takes place.
> Of course, that also means it's a prime place for an optimization that will
> evaluate eagerly for known receiver types and so (over time) optimizations
> were added, but many of the optimizations that may make sense in an
> interpreter have very different tradeoffs in the jit. For a jit to generate
> the level of optimization makes no sense because the code size simply
> explodes at no benefit if the inline caches are any good (ours *are* the best
> Eliot knows how to do and that is a meaningful statement).
> On to a finer point. The terminology "real message send" is misleading.
> Generally, we (the VM hackers) mean by "real" send a send that requires a
> method activation, i.e., the creation of a context, but *not* the lookup of
> the method. That excludes for example all (successful) primitives from being
> "real sends", and as a consequence writing "1 + 2" is not a real send by that
> measure (with or without the bytecode present) since the primitive will be
> executed successfully and no "real" send (method activation) has taken place.
> To make matters more complicated, when we talk about "real" sends in the
> context of thread switches, semaphores and critical sections, what we mean is
> whether there is a suspension point in the send or not. Obviously, some
> primitives (#suspend, #yield) must have suspension points so not all
> activation-free methods are also suspension-point-free. I am not entirely
> sure what the current set of rules for suspension points in Cog is; in the
> interpreter it was part of the activation sequence so any primitive that
> isn't process related would not have a suspension point but I don't know if
> that's still true in Cog.
Thanks, this was very informative.
> - Andreas
More information about the Squeak-dev