Hi All,<div><br></div><div>    so the performance benefit of the special selectors is interesting.  One thing the interpreter does on all relational special selectors #= #~= #&lt; #&lt;= #&gt; #&gt;= is statically predict SmallIntegers and/or Floats and look ahead for a following conditional branch, evaluating the branch immediately, avoiding reifying the result of the relational as either true or false and later testing for it, hence jumping directly on the condition codes.</div>
<div><br></div><div>e.g.</div><div><div>bytecodePrimLessThan</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>| rcvr arg aBool |</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>rcvr := self internalStackValue: 1.</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>arg := self internalStackValue: 0.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>(self areIntegers: rcvr and: arg) ifTrue:</div><div>
<span class="Apple-tab-span" style="white-space:pre">                </span>[&quot;The C code can avoid detagging since tagged integers are still signed.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> But this means the simulator must override to do detagging.&quot;</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>^self cCode: [self booleanCheat: rcvr &lt; arg]</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>inSmalltalk: [self booleanCheat: (objectMemory integerValueOf: rcvr) &lt; (objectMemory integerValueOf: arg)]].</div>
<div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self initPrimCall.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>aBool := self primitiveFloatLess: rcvr thanArg: arg.</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>self successful ifTrue: [^ self booleanCheat: aBool].</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>messageSelector := self specialSelector: 2.</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>argumentCount := 1.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self normalSend</div><div><br></div><div><div>booleanCheat: cond</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>&quot;cheat the interpreter out of the pleasure of handling the next bytecode IFF it is a jump-on-boolean. Which it is, often enough when the current bytecode is something like bytecodePrimEqual&quot;</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>&lt;inline: true&gt;</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>cond</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>ifTrue: [self booleanCheatTrue]</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>ifFalse: [self booleanCheatFalse]</div></div><div><br></div><div><div>booleanCheatFalse</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&quot;cheat the interpreter out of the pleasure of handling the next bytecode IFF it is a jump-on-boolean. Which it is, often enough when the current bytecode is something like bytecodePrimEqual&quot;</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>| bytecode offset |</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&lt;sharedCodeNamed: &#39;booleanCheatFalse&#39; inCase: 179&gt;</div>
<div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>bytecode := self fetchByte.  &quot;assume next bytecode is jumpIfFalse (99%)&quot;</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self internalPop: 2.</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>(bytecode &lt; 160 and: [bytecode &gt; 151]) ifTrue:  &quot;short jumpIfFalse&quot;</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>[^self jump: bytecode - 151].</div>
<div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>bytecode = 172 ifTrue:  &quot;long jumpIfFalse&quot;</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>[offset := self fetchByte.</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>^self jump: offset].</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&quot;not followed by a jumpIfFalse; undo instruction fetch and push boolean result&quot;</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>localIP := localIP - 1.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self fetchNextBytecode.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self internalPush: objectMemory falseObject</div>
</div><div><br></div><div><div>booleanCheatTrue</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&quot;cheat the interpreter out of the pleasure of handling the next bytecode IFF it is a jump-on-boolean. Which it is, often enough when the current bytecode is something like bytecodePrimEqual&quot;</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>| bytecode |</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&lt;sharedCodeNamed: &#39;booleanCheatTrue&#39; inCase: 178&gt;</div><div>
<br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>bytecode := self fetchByte.  &quot;assume next bytecode is jumpIfFalse (99%)&quot;</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self internalPop: 2.</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>(bytecode &lt; 160 and: [bytecode &gt; 151]) ifTrue:  &quot;short jumpIfFalse&quot;</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>[^self fetchNextBytecode].</div>
<div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>bytecode = 172 ifTrue: &quot;long jumpIfFalse&quot;</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>[self fetchByte.</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>^self fetchNextBytecode].</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>&quot;not followed by a jumpIfFalse; undo instruction fetch and push boolean result&quot;</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>localIP := localIP - 1.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self fetchNextBytecode.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>self internalPush: objectMemory trueObject</div>
</div><div><br></div><div><br></div>Until yesterday Cog didn&#39;t do this for jitted code.  The conversation about using #= for testing got me motivated to implement it.  Note that VisualWorks&#39; HPS VM does something even but more aggressive than booleanCheat:.  So what are we talking about?  Here&#39;s my micro-benchmark:</div>
<div><br></div><div>Time millisecondsToRun: [1 to: 100000000 do: [:i| ]]</div><div><br></div><div>The bytecode compiler optimizes the inner loop to code equivalent to</div><div><br></div><div>| i |</div><div>i := 1.</div>
<div>[i &lt;= 100000000] whileTrue: [i := i + 1]</div><div><br></div><div>Here&#39;s the Squeak bytecode:</div><div><br></div><div><div>25 &lt;76&gt; pushConstant: 1</div><div>26 &lt;68&gt; popIntoTemp: 0</div><div>27 &lt;10&gt; pushTemp: 0</div>
<div>28 &lt;20&gt; pushConstant: 100000000</div><div>29 &lt;B4&gt; send: &lt;=</div><div>30 &lt;9D&gt; jumpFalse: 37</div><div>31 &lt;10&gt; pushTemp: 0</div><div>32 &lt;76&gt; pushConstant: 1</div><div>33 &lt;B0&gt; send: +</div>
<div>34 &lt;68&gt; popIntoTemp: 0</div><div>35 &lt;A3 F6&gt; jumpTo: 27</div></div><div>37:</div><div><br></div><div>And here&#39;s the VisualWorks bytecode:</div><div><div> 6 &lt;4A&gt; push 1</div><div> 7 &lt;4C&gt; store local 0; pop</div>
<div> 8 &lt;67&gt; loop head</div><div> 9 &lt;10&gt; push local 0</div><div>10 &lt;1C&gt; push 100000000</div><div>11 &lt;A4&gt; send &lt;=</div><div>12 &lt;C4&gt; jump false 18</div><div>13 &lt;10&gt; push local 0</div><div>
14 &lt;C8&gt; push 1; send +</div><div>15 &lt;4C&gt; store local 0; pop</div><div>16 &lt;E3 F6&gt; jump 8</div></div><div>18:</div><div><br></div><div>Note that loopHead is a no-op that allows the HPS JIT to be one pass; it tells the JIT that there is a backward branch to this instruction and so knows that loopHead is a control-flow join, which means that the registers that cache the receiver and its base pointer (VW has an indirection from the object header to an object body) must be reloaded if needed.</div>
<div><br></div><div>So the current version of Cog generates the following code for the loop:</div><div><br></div><div><div>25 &lt;76&gt; pushConstant: 1</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ea4: movl $0x00000003, %eax : B8 03 00 00 00 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ea9: pushl %eax : 50 </div><div>26 &lt;68&gt; popIntoTemp: 0</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1eaa: popl %eax : 58 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1eab: movl %eax, %ss:0xfffffff0(%ebp) : 89 45 F0 </div><div>27 &lt;10&gt; pushTemp: 0</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1eae: movl %ss:0xfffffff0(%ebp), %eax : 8B 45 F0 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1eb1: pushl %eax : 50 </div><div>28 &lt;20&gt; pushConstant: 100000000</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1eb2: pushl $0x0bebc201 : 68 01 C2 EB 0B </div>
<div>29 &lt;B4&gt; send: &lt;=</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1eb7: movl %ss:0x4(%esp), %edx : 8B 54 24 04 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ebb: movl $0x0045a458=#&lt;=, %ecx : B9 58 A4 45 00 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ec0: call .+0xfff5e5cb (0x00000490=ceSend1Args) : E8 CB E5 F5 FF </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>IsSendCall:</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ec5: pushl %edx : 52 </div><div>30 &lt;9D&gt; jumpFalse: 37</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ec6: popl %eax : 58 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ec7: subl $0x00172270=false, %eax : 2D 70 22 17 00 </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>IsObjectReference:</div><div>
<span class="Apple-tab-span" style="white-space:pre">                </span>a1ecc: jz .+0x0000003d (0x000a1f0b=16rA1E50@BB) : 74 3D </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ece: cmpl $0x00000008, %eax : 83 F8 08 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ed1: jz .+0x0000000b (0x000a1ede=16rA1E50@8E) : 74 0B </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ed3: addl $0x00172270=false, %eax : 05 70 22 17 00 </div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>IsObjectReference:</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ed8: pushl %eax : 50 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ed9: call .+0xfff5e902 (0x000007e0=ceSendMustBeBooleanTrampoline) : E8 02 E9 F5 FF </div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>HasBytecodePC:</div><div>31 &lt;10&gt; pushTemp: 0</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ede: movl %ss:0xfffffff0(%ebp), %eax : 8B 45 F0 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ee1: pushl %eax : 50 </div><div>32 &lt;76&gt; pushConstant: 1</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ee2: movl $0x00000003, %eax : B8 03 00 00 00 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ee7: pushl %eax : 50 </div><div>33 &lt;B0&gt; send: +</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ee8: movl %ss:0x4(%esp), %edx : 8B 54 24 04 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1eec: movl $0x0045ae64=#+, %ecx : B9 64 AE 45 00 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ef1: call .+0xfff5e59a (0x00000490=ceSend1Args) : E8 9A E5 F5 FF </div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>IsSendCall:</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ef6: pushl %edx : 52 </div><div>34 &lt;68&gt; popIntoTemp: 0</div><div>
<span class="Apple-tab-span" style="white-space:pre">                </span>a1ef7: popl %eax : 58 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1ef8: movl %eax, %ss:0xfffffff0(%ebp) : 89 45 F0 </div><div>35 &lt;A3 F6&gt; jumpTo: 27</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1efb: movl %ds:0x0013aafc=&amp;stackLimit, %eax : A1 FC AA 13 00 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1f00: cmpl %eax, %esp : 39 C4 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a1f02: jnb .+0xffffffaa (0x000a1eae=16rA1E50@5E) : 73 AA </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1f04: call .+0xfff5e907 (0x00000810=ceCheckForInterruptsTrampoline) : E8 07 E9 F5 FF </div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>HasBytecodePC:</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a1f09: jmp .+0xffffffa3 (0x000a1eae=16rA1E50@5E) : EB A3 </div><div>
37:<span class="Apple-tab-span" style="white-space:pre">        </span>0x000a1f0b/16rA1E50@BB:</div></div><div><br></div><div>And here&#39;s the primitive part of the SmallInteger&gt;#&lt;= method; the SmallInteger&lt;#+ method is similar.  I&#39;ll omit it for brevity.</div>
<div><br></div><div><div><span class="Apple-tab-span" style="white-space:pre">        </span>entry: (check that the receiver matches the inline cache)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>00002498: movl %edx, %eax : 89 D0 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>0000249a: andl $0x00000001, %eax : 83 E0 01 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>0000249d: jnz .+0x00000010 (0x000024af=&lt;=@37) : 75 10 (jump if the receiver is a SmallInteger, which in our case it is)</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>0000249f: movl %ds:(%edx), %eax : 8B 02 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024a1: shrl $0x0a, %eax : C1 E8 0A </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024a4: andl $0x0000007c, %eax : 83 E0 7C </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024a7: jnz .+0x00000006 (0x000024af=&lt;=@37) : 75 06 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024a9: movl %ds:0xfffffffc(%edx), %eax : 8B 42 FC </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024ac: andl $0xfffffffc, %eax : 83 E0 FC </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024af: cmpl %ecx, %eax : 39 C8                                  (compare the receiver&#39;s tags against the inline cache ecx, which in our case will match)</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024b1: jnz .+0xffffffdf (0x00002492=&lt;=@1A) : 75 DF </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>noCheckEntry: (SmallInteger primitive #&lt;=)</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024b3: movl %ss:0x4(%esp), %eax : 8B 44 24 04 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024b7: movl %eax, %ecx : 89 C1 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024b9: andl $0x00000001, %eax : 83 E0 01 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024bc: jz .+0x00000014 (0x000024d2=&lt;=@5A) : 74 14 (is the argument a SmallInteger, which in our case it will be)</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024be: cmpl %ecx, %edx : 39 CA </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024c0: jle .+0x00000008 (0x000024ca=&lt;=@52) : 7E 08 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024c2: movl $0x00172270=false, %edx : BA 70 22 17 00 (answer the false object)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>IsObjectReference:</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>000024c7: ret $0x0008 : C2 08 00 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024ca: movl $0x00172278=true, %edx : BA 78 22 17 00 (answer the true object)</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>IsObjectReference:</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024cf: ret $0x0008 : C2 08 00 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>000024d2:</div>
</div><div><br></div><div>You can see that the Cog code generator is extremely naive; it&#39;s generating RISC code.  There are no compares against memory; only against registers, etc.</div><div><br></div><div>The question I want you to ask yourself is how much faster the loop will go if we add code to short-circuit the send of #&lt;= and the comparison against true and false with a tag test and a direct comparison.  Try answering it as we go along.  I&#39;ll answer it below but try and answer it yourself.  Basically we should speed up about a third of the loop substantially where the loop has three main parts, a) the compare and branch [i &lt;= 100000000] whileTrue:, b) the increment i := i + 1, and c) the backward branch at the end of the while loop which checks the stackLimit to break out if there is an event (e.g. ctrl-.).</div>
<div><br></div><div>OK, so here&#39;s the code with the booleanCheat implemented in the JIT:</div><div><div><br></div><div><div>25 &lt;76&gt; pushConstant: 1</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52cc: movl $0x00000003, %eax : B8 03 00 00 00 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a52d1: pushl %eax : 50 </div><div>26 &lt;68&gt; popIntoTemp: 0</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52d2: popl %eax : 58 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a52d3: movl %eax, %ss:0xfffffff0(%ebp) : 89 45 F0 </div><div>27 &lt;10&gt; pushTemp: 0</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52d6: movl %ss:0xfffffff0(%ebp), %eax : 8B 45 F0 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a52d9: pushl %eax : 50 </div><div>28 &lt;20&gt; pushConstant: 100000000</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52da: pushl $0x0bebc201 : 68 01 C2 EB 0B </div>
<div>29 &lt;B4&gt; send: &lt;=</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52df: movl %ss:(%esp), %esi : 8B 34 24 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52e2: movl %esi, %eax : 89 F0 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a52e4: movl %ss:0x4(%esp), %edx : 8B 54 24 04 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52e8: andl %edx, %eax : 23 C2 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a52ea: andl $0x00000001, %eax : 83 E0 01                          (are receiver and arg SmallIntegers, which they are)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52ed: jz .+0x00000009 (0x000a52f8=16rA5278@80) : 74 09 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a52ef: addl $0x00000008, %esp : 83 C4 08 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52f2: cmpl %esi, %edx : 39 F2                                           (compare directly)</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a52f4: jnle .+0x00000056 (0x000a534c=16rA5278@D4) : 7F 56 (jump on condition codes)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52f6: jmp .+0x00000027 (0x000a531f=16rA5278@A7) : EB 27 (jump past the send and the jumpFalse:)</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a52f8: movl %ss:0x4(%esp), %edx : 8B 54 24 04 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a52fc: movl $0x0045a458, %ecx : B9 58 A4 45 00 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a5301: call .+0xfff5b18a (0x00000490=ceSend1Args) : E8 8A B1 F5 FF </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>IsSendCall:</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a5306: pushl %edx : 52 </div><div>30 &lt;9D&gt; jumpFalse: 37</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5307: popl %eax : 58 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a5308: subl $0x00172270=false, %eax : 2D 70 22 17 00 </div><div><span class="Apple-tab-span" style="white-space:pre">        </span>IsObjectReference:</div><div>
<span class="Apple-tab-span" style="white-space:pre">                </span>a530d: jz .+0x0000003d (0x000a534c=16rA5278@D4) : 74 3D </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a530f: cmpl $0x00000008, %eax : 83 F8 08 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a5312: jz .+0x0000000b (0x000a531f=16rA5278@A7) : 74 0B </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5314: addl $0x00172270=false, %eax : 05 70 22 17 00 </div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>IsObjectReference:</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5319: pushl %eax : 50 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a531a: call .+0xfff5b4c1 (0x000007e0=ceSendMustBeBooleanTrampoline) : E8 C1 B4 F5 FF </div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>HasBytecodePC:</div><div>31 &lt;10&gt; pushTemp: 0</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a531f: movl %ss:0xfffffff0(%ebp), %eax : 8B 45 F0 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a5322: pushl %eax : 50 </div><div>32 &lt;76&gt; pushConstant: 1</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5323: movl $0x00000003, %eax : B8 03 00 00 00 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a5328: pushl %eax : 50 </div><div>33 &lt;B0&gt; send: +</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5329: movl %ss:0x4(%esp), %edx : 8B 54 24 04 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a532d: movl $0x0045ae64=#+, %ecx : B9 64 AE 45 00 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5332: call .+0xfff5b159 (0x00000490=ceSend1Args) : E8 59 B1 F5 FF </div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>IsSendCall:</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5337: pushl %edx : 52 </div><div>34 &lt;68&gt; popIntoTemp: 0</div><div>
<span class="Apple-tab-span" style="white-space:pre">                </span>a5338: popl %eax : 58 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5339: movl %eax, %ss:0xfffffff0(%ebp) : 89 45 F0 </div><div>35 &lt;A3 F6&gt; jumpTo: 27</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a533c: movl %ds:0x0013aafc=&amp;stackLimit, %eax : A1 FC AA 13 00 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5341: cmpl %eax, %esp : 39 C4 </div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>a5343: jnb .+0xffffff91 (0x000a52d6=16rA5278@5E) : 73 91 </div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a5345: call .+0xfff5b4c6 (0x00000810=ceCheckForInterruptsTrampoline) : E8 C6 B4 F5 FF </div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>HasBytecodePC:</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>a534a: jmp .+0xffffff8a (0x000a52d6=16rA5278@5E) : EB 8A </div></div>
<div><br></div><div>So roughly 1/3 of the loop has been sped up substantially.  How much speedup?</div><div><br></div><div>2.7%.  2.7 measly percent.  A good 2 - 3 hours work and 2.7 measly % ?!?!?  i.e. 691 milliseconds fell to 672 milliseconds (and the measurements are nicely repeatable).</div>
<div><br></div><div>Well, one reason for the limited performance increase could be that the event check at the backward branch is being taken a lot and dominating costs.  So what happens if I change the heartbeat from 2KHz to 20KHz?  672 falls to 664, so only 9 milliseconds or so is due to the stack limit event check.</div>
<div><br></div><div>Perhaps the x86 is so good at optimizing the code that it can&#39;t be sped up.  Well, let&#39;s have a look at HPS&#39;s performance.  It is *4* times faster, 168 ms vs 672 (that&#39;s *exactly* 4 times faster :) ).  So what code does HPS generate?  First its back-end is less naive; it doesn&#39;t move intermediate results through registers all the time.  But most significantly it is able to know that both the 100000000 and the + 1 are SmallIntegers because it delays generating code until it gets to a send.  So its code is a /lot/ better.  It short-circuits bth the compare and branch and the increment.  Here it is (remember that Squeak has only one tagged type, SmallInteger with tag 1, and 32-bit VW has two tagged types SmallInteger and Character with tags 3 and 1 respectively, so in VW 1 == 0x7):</div>
<div><br></div><div><div> 6 &lt;4A&gt; push 1</div><div> 7 &lt;4C&gt; store local 0; pop</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@039:<span class="Apple-tab-span" style="white-space:pre">        </span>xor rTemp,rTemp<span class="Apple-tab-span" style="white-space:pre">        </span>! 33 c0</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@03b:<span class="Apple-tab-span" style="white-space:pre">        </span>movb $7,%al<span class="Apple-tab-span" style="white-space:pre">        </span>! b0 07</div><div>
<span class="Apple-tab-span" style="white-space:pre">        </span>nm@03d:<span class="Apple-tab-span" style="white-space:pre">        </span>mov rTemp,-0x10(bFrame)<span class="Apple-tab-span" style="white-space:pre">        </span>! 89 45 f0</div>
<div> 8 &lt;67&gt; loop head</div><div> 9 &lt;10&gt; push local 0</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@040:<span class="Apple-tab-span" style="white-space:pre">        </span>mov -0x10(bFrame),rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 8b 5d f0</div>
<div>10 &lt;1C&gt; push 100000000</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@043:<span class="Apple-tab-span" style="white-space:pre">        </span>mov $0x17d78403,rArg1<span class="Apple-tab-span" style="white-space:pre">        </span>! be 03 84 d7 17</div>
<div>11 &lt;A4&gt; send &lt;=</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@048:<span class="Apple-tab-span" style="white-space:pre">        </span>testb $2,%bl<span class="Apple-tab-span" style="white-space:pre">        </span>! f6 c3 02 a.k.a. testb $2,rReceiver</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@04b:<span class="Apple-tab-span" style="white-space:pre">        </span>jz nm@056<span class="Apple-tab-span" style="white-space:pre">        </span>! 74 09</div><div>
<span class="Apple-tab-span" style="white-space:pre">        </span>nm@04d:<span class="Apple-tab-span" style="white-space:pre">        </span>cmp rArg1,rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 3b de</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@04f:<span class="Apple-tab-span" style="white-space:pre">        </span>jle nm@075<span class="Apple-tab-span" style="white-space:pre">        </span>! 7e 24</div><div>
<span class="Apple-tab-span" style="white-space:pre">        </span>nm@051:<span class="Apple-tab-span" style="white-space:pre">        </span>jmp nm@0ab<span class="Apple-tab-span" style="white-space:pre">        </span>! e9 55 00 00 00</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@056:<span class="Apple-tab-span" style="white-space:pre">        </span>mov $0x16a8ec6c,rClass<span class="Apple-tab-span" style="white-space:pre">        </span>! ba 6c ec a8 16</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@05b:<span class="Apple-tab-span" style="white-space:pre">        </span>call _81080=send1Args<span class="Apple-tab-span" style="white-space:pre">        </span>! e8 28 e7 6b ea</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>map: 0x3a: send1(26) #&lt;=</div><div>vpc 12:</div><div>12 &lt;C4&gt; jump false 18</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@060:<span class="Apple-tab-span" style="white-space:pre">        </span>cmp $0x16b33da4,rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 81 fb a4 3d b3 16</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@066:<span class="Apple-tab-span" style="white-space:pre">        </span>jz nm@0ab<span class="Apple-tab-span" style="white-space:pre">        </span>! 74 43</div><div>
<span class="Apple-tab-span" style="white-space:pre">        </span>nm@068:<span class="Apple-tab-span" style="white-space:pre">        </span>cmp $0x16da90e4,rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 81 fb e4 90 da 16</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@06e:<span class="Apple-tab-span" style="white-space:pre">        </span>jz nm@075<span class="Apple-tab-span" style="white-space:pre">        </span>! 74 05</div><div>
<span class="Apple-tab-span" style="white-space:pre">        </span>nm@070:<span class="Apple-tab-span" style="white-space:pre">        </span>call _159cadd8<span class="Apple-tab-span" style="white-space:pre">        </span>! e8 6b 84 00 00</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@075:<span class="Apple-tab-span" style="white-space:pre">        </span>mov -0x10(bFrame),rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 8b 5d f0</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@078:<span class="Apple-tab-span" style="white-space:pre">        </span>testb $2,%bl<span class="Apple-tab-span" style="white-space:pre">        </span>! f6 c3 02 a.k.a. testb $2,rReceiver</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@07b:<span class="Apple-tab-span" style="white-space:pre">        </span>jz nm@085<span class="Apple-tab-span" style="white-space:pre">        </span>! 74 08</div><div>
13 &lt;10&gt; push local 0</div><div>14 &lt;C8&gt; push 1; send +</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@07d:<span class="Apple-tab-span" style="white-space:pre">        </span>add $4,rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 83 c3 04</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@080:<span class="Apple-tab-span" style="white-space:pre">        </span>jno nm@092<span class="Apple-tab-span" style="white-space:pre">        </span>! 71 10</div><div>
<span class="Apple-tab-span" style="white-space:pre">        </span>nm@082:<span class="Apple-tab-span" style="white-space:pre">        </span>sub $4,rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 83 eb 04</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@085:<span class="Apple-tab-span" style="white-space:pre">        </span>push $7<span class="Apple-tab-span" style="white-space:pre">        </span>! 6a 07</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@087:<span class="Apple-tab-span" style="white-space:pre">        </span>pop rArg1<span class="Apple-tab-span" style="white-space:pre">        </span>! 5e</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@088:<span class="Apple-tab-span" style="white-space:pre">        </span>mov $0x16bbab34,rClass<span class="Apple-tab-span" style="white-space:pre">        </span>! ba 34 ab bb 16</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@08d:<span class="Apple-tab-span" style="white-space:pre">        </span>call _81080=send1Args<span class="Apple-tab-span" style="white-space:pre">        </span>! e8 f6 e6 6b ea</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>map: 0x22: send1(2) #+</div><div>15 &lt;4C&gt; store local 0; pop</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@092:<span class="Apple-tab-span" style="white-space:pre">        </span>mov rReceiver,-0x10(bFrame)<span class="Apple-tab-span" style="white-space:pre">        </span>! 89 5d f0</div>
<div>16 &lt;E3 F6&gt; jump 8</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@095:<span class="Apple-tab-span" style="white-space:pre">        </span>cmp 0xfb190,bSP<span class="Apple-tab-span" style="white-space:pre">        </span>! 3b 25 90 b1 0f 00</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@09b:<span class="Apple-tab-span" style="white-space:pre">        </span>jae nm@040<span class="Apple-tab-span" style="white-space:pre">        </span>! 0f 83 9f ff ff ff</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@0a1:<span class="Apple-tab-span" style="white-space:pre">        </span>call _80d30<span class="Apple-tab-span" style="white-space:pre">        </span>! e8 92 e3 6b ea</div>
<div>vpc 18:</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@0a6:<span class="Apple-tab-span" style="white-space:pre">        </span>jmp nm@040<span class="Apple-tab-span" style="white-space:pre">        </span>! e9 95 ff ff ff</div>
</div><div><br></div><div><br></div><div>Interesting.  VW executes the following instructions around the loop:</div><div><br></div><div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@040:<span class="Apple-tab-span" style="white-space:pre">        </span>mov -0x10(bFrame),rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 8b 5d f0</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@043:<span class="Apple-tab-span" style="white-space:pre">        </span>mov $0x17d78403,rArg1<span class="Apple-tab-span" style="white-space:pre">        </span>! be 03 84 d7 17</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@048:<span class="Apple-tab-span" style="white-space:pre">        </span>testb $2,%bl<span class="Apple-tab-span" style="white-space:pre">        </span>! f6 c3 02 a.k.a. testb $2,rReceiver</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@04b:<span class="Apple-tab-span" style="white-space:pre">        </span>jz nm@056<span class="Apple-tab-span" style="white-space:pre">        </span>! 74 09</div><div>
<span class="Apple-tab-span" style="white-space:pre">        </span>nm@04d:<span class="Apple-tab-span" style="white-space:pre">        </span>cmp rArg1,rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 3b de</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@04f:<span class="Apple-tab-span" style="white-space:pre">        </span>jle nm@075<span class="Apple-tab-span" style="white-space:pre">        </span>! 7e 24</div><div>
<span class="Apple-tab-span" style="white-space:pre">        </span>nm@051:<span class="Apple-tab-span" style="white-space:pre">        </span>jmp nm@0ab<span class="Apple-tab-span" style="white-space:pre">        </span>! e9 55 00 00 00</div>
<div>...</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@07d:<span class="Apple-tab-span" style="white-space:pre">        </span>add $4,rReceiver<span class="Apple-tab-span" style="white-space:pre">        </span>! 83 c3 04</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@080:<span class="Apple-tab-span" style="white-space:pre">        </span>jno nm@092<span class="Apple-tab-span" style="white-space:pre">        </span>! 71 10</div><div>
...</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@092:<span class="Apple-tab-span" style="white-space:pre">        </span>mov rReceiver,-0x10(bFrame)<span class="Apple-tab-span" style="white-space:pre">        </span>! 89 5d f0</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@095:<span class="Apple-tab-span" style="white-space:pre">        </span>cmp 0xfb190,bSP<span class="Apple-tab-span" style="white-space:pre">        </span>! 3b 25 90 b1 0f 00</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>nm@09b:<span class="Apple-tab-span" style="white-space:pre">        </span>jae nm@040<span class="Apple-tab-span" style="white-space:pre">        </span>! 0f 83 9f ff ff ff</div>
</div><div><br></div><div>12 instructions, one read and one write. Cog executes many more, quite a few of them reads and writes.  How I itch to find the time to do delayed code generation/stack-to-register mapping in Cog...</div>
<div><br></div><div>best,</div><div>Eliot</div><div><br></div><div class="gmail_quote">On Tue, Nov 16, 2010 at 3:32 PM, Levente Uzonyi <span dir="ltr">&lt;<a href="mailto:leves@elte.hu">leves@elte.hu</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">On Tue, 16 Nov 2010, Juan Vuletich wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi Levente,<br>
<br>
Levente Uzonyi wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi,<br>
<br>
I&#39;m mostly ready with this cleanup, only a few methods left in the image that use #== for integer comparison. Some of them must use #==, others may be changed, but I wasn&#39;t sure if the code will work if it&#39;s changed or not. If you&#39;d like to check these methods, then evaluate the following in a workspace:<br>

<br>
... code here...<br>
<br>
Cheers,<br>
Levente<br>
</blockquote>
<br>
Thanks for the snippet! It is now a method in Cuis. I also checked a bit on trunk. In all senders of #nextObject you can apply the pattern in #allObjectsDo:. Instead of assuming == 0 for last #nextObject, it assumes that Object new will go at the end. If that ever changed, a few places would need fixing...<br>

</blockquote>
<br>
I&#39;m not sure if it&#39;s ok to use that pattern in ImageSegment. Even if it&#39;s ok, the code is so messy, that it seems to be hard to apply the pattern without breaking the code.<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
As an experiment, in #allObjectsDo: I tried to remove the Object new stuff and replace with &#39;[ 0 = object and: [ object isMemberOf: SmallInteger ]] whileFalse: &#39;, but my test became extremely slow. I suspect #= is sending the message even if it has its own bytecode... So, the only method that remains with the &#39;0 ==&#39; pattern in Cuis is #critical:ifLocked: , as I&#39;m not sure if we can clean it.<br>

</blockquote>
<br>
#= is a special selector, so I&#39;m sure it won&#39;t send a message if it doesn&#39;t have to. It&#39;s possible that #= is a bit slower than #== because it has to do some extra checks, but the difference is probably neglible. Here&#39;s a benchmark:<br>

<br>
| offset equality identity |<br>
Smalltalk garbageCollect.<br>
offset := [ 1 to: 1000000 do: [ :i | ] ] timeToRun.<br>
equality := [ :x | [ 1 to: 1000000 do: [ :i | 0 = x ] ] timeToRun ].<br>
identity := [ :x | [ 1 to: 1000000 do: [ :i | 0 == x ] ] timeToRun ].<br>
{ 0. 1. SmallInteger maxVal. SmallInteger maxVal + 1. nil. Object new. 0.0. Array new. 1/2 } collect: [ :each |<br>
        each -&gt; ({<br>
                equality value: each.<br>
                identity value: each.<br>
                equality value: each.<br>
                identity value: each.<br>
                equality value: each.<br>
                identity value: each } - offset) ].<br>
<br>
And my results on CogVM:<br>
<br>
{<br>
        0-&gt;#(3 2 3 1 3 2).<br>
        1-&gt;#(2 4 3 0 3 4).<br>
        1073741823-&gt;#(3 3 2 1 3 5).<br>
        1073741824-&gt;#(221 4 223 1 223 4).<br>
        nil-&gt;#(14 4 14 0 15 4).<br>
        an Object-&gt;#(14 5 13 1 14 4).<br>
        0.0-&gt;#(622 5 623 2 624 4).<br>
        #()-&gt;#(16 5 14 1 16 4).<br>
        (1/2)-&gt;#(260 4 259 1 258 5)<br>
}<br>
<br>
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.<br>
<br>
Another way to implement #allObjectsDo: without the marker object is to replace the loop condition with: object class == SmallInteger. It&#39;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.<br>

<br>
<br>
Levente<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Cheers,<br>
Juan Vuletich<br>
<br>
<br>
</blockquote>
<br>
</blockquote></div><br></div>