But the issue is /not/ whether there is a send or not. The issue is what the behaviour of the primitive code is. In the interpreter #= will short-circuit (avoid the send) if both the receiver and the argument are either a SmallInteger or a Float. In the JIT the primitive will not fail if the receiver and argument are both SmallIntegers or Floats or if the receiver is a Float and the argument is an Integer, but will fail if the receiver is a SmallInteger and the argument is a Float.
In general the VM is free to fail for non-matching numeric types (this is historical, derived from the blue book) so I don't feel Cog is at fault here. Certainly it is not answering incorrect results; it is simply taking more sends to produce the result in some circumstances. I think in cases like this (where you're enumerating over all objects) using #== is a wiser choice.
HTH
It's possible that #= is a bit slower than #== because it has to do some extra checks, but the difference is probably neglible. Here's a benchmark:
| offset equality identity |
Smalltalk garbageCollect.
offset := [ 1 to: 1000000 do: [ :i | ] ] timeToRun.
equality := [ :x | [ 1 to: 1000000 do: [ :i | 0 = x ] ] timeToRun ].
identity := [ :x | [ 1 to: 1000000 do: [ :i | 0 == x ] ] timeToRun ].
{ 0. 1. SmallInteger maxVal. SmallInteger maxVal + 1. nil. Object new. 0.0. Array new. 1/2 } collect: [ :each |
each -> ({
equality value: each.
identity value: each.
equality value: each.
identity value: each.
equality value: each.
identity value: each } - offset) ].
And my results on CogVM:
{
0->#(3 2 3 1 3 2).
1->#(2 4 3 0 3 4).
1073741823->#(3 3 2 1 3 5).
1073741824->#(221 4 223 1 223 4).
nil->#(14 4 14 0 15 4).
an Object->#(14 5 13 1 14 4).
0.0->#(622 5 623 2 624 4).
#()->#(16 5 14 1 16 4).
(1/2)->#(260 4 259 1 258 5)
}
I'd do many more iterations. I wouldn't put any faith any millisecond numbers that are less than 3 digits (100 ms).
So the cause of the slowdown in your #allObjectsDo: implementation is that #= is only fast if both the receiver and the argument are SmallIntegers, otherwise there will be message sends.
Another way to implement #allObjectsDo: without the marker object is to replace the loop condition with: object class == SmallInteger. It's actually the same as your implementation without the #= check. #isMemberOf: is optimized to non-real sends. This is as fast as the current implementation on my pc.
Levente
Cheers,
Juan Vuletich