<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Apr 3, 2015 at 12:03 PM, Eliot Miranda <span dir="ltr">&lt;<a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Fri, Apr 3, 2015 at 11:18 AM, Eliot Miranda <span dir="ltr">&lt;<a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">Hi Ryan, Hi Tim, Hi Clément, and anyone else interested in Cogit arcana,<div><br></div><div>   Sista needs a directed super send bytecode.  A normal super bytecode takes the class above which to start the lookup implicitly from the method class (the last literal in a method).  A directed super send takes the class above which to start the lookup as an explicit parameter.  In Ssta&#39;s case we&#39;re pushing the class association on the stack immediately before the super send bytecode, and marking the super send bytecode as directed using a flag bit in one of the extensions.</div><div><br></div><div>Compiling a directed super is trivial; simply make the literal variable that was notionally pushed on the stack an argument of a new ceSendDirectedSuper trampoline.  But this implies that when a linked directed super send bytecode is unlinked (e.g. method redefinition or method zone compaction) we can map back to this ceSendDirectedSuper tramp[oline.</div><div><br></div><div>Up until now, the different send trampolines have been identified by looking at the alignment of the linked call instruction; every different kind of send needs a different entry point in the target method at a different alignment.  This worked well when there were only self and super sends.  It also meant that there was only a single method map type for sends, which kept the method metadata small.  Now Newspeak has two more send types; Sista will use three.  On x86 each alignment can be generated by adding a 1 byte nop in the right place.  Methods themselves are aligned on 8-byte boundaries, so the scheme would extend to 8 different send types at a pinch on x86.  Of course on ARM this doesn&#39;t work well at all; instructions are 4 bytes, and so 8 byte alignment gives only two different alignments, and we were planning to extend the method alignment to e.g. 16 bytes.</div><div><br></div><div>But all this puts extra code in the entry sequence albeit only in the form of nops.  But unlinking is extremely rare so we&#39;re letting the tail wag the dog.  Instead, I&#39;m going to revise the method metadata scheme so there&#39;s a modifier byte we can use to further distinguish send types.  We can still distinguish checked sends from unchecked sends based on alignment.  But we can distinguish between the different checked sends and the different unchecked send types by using one map code to code for a prefix.</div><div><br></div><div>A map byte has a 5 bit displacement (the distance in machine code units to the next map byte&#39;s target), and a 3 bit code in the most significant bits.  Here&#39;s the existing assignments:</div><div><br></div><div><div><span style="white-space:pre-wrap">        </span>IsSendCall := 7.</div><div><span style="white-space:pre-wrap">        </span>IsRelativeCall := 6.</div><div><span style="white-space:pre-wrap">        </span>HasBytecodePC := 5.</div><div><span style="white-space:pre-wrap">        </span>IsAbsPCReference := 4.</div><div><span style="white-space:pre-wrap">        </span>IsObjectReference := 3.</div><div><span style="white-space:pre-wrap">        </span>IsNSSendCall := NewspeakVM ifTrue: [2].</div><div><span style="white-space:pre-wrap">        </span>IsDisplacementX2N := 1.</div><div><span style="white-space:pre-wrap">        </span>IsDisplacement := 0.</div><div><span style="white-space:pre-wrap">        </span>AnnotationShift := 5.</div><div><br></div><div>So if we nuke IsNSSendCall we can do e.g.</div><div><span style="white-space:pre-wrap">        AnnotationExtension := 2</span></div><div><span style="white-space:pre-wrap">interpret the displacement of an </span><span style="white-space:pre-wrap">AnnotationExtension as 0, and use the 5-bit field to extend the type of the subsequent map byte.  We then</span><span style="white-space:pre-wrap"> use two map bytes for exotic sends, suddenly making lots of send types possible without contortions.</span></div><div>--  </div><div>best,<div>Eliot</div></div></div></div></blockquote><div><br></div></div></div><div>And this is an example of how the simulator makes life so easy.  10 minutes work to derive dynamic frequencies of all annotations including the displacement ones that are excluded from the extant mapFor:do:</div></div><div class="gmail_extra"><br></div><div class="gmail_extra">| dynamicFrequencies |</div><div class="gmail_extra">dynamicFrequencies := Bag new.</div><div class="gmail_extra">methodZone methodsDo:</div><div class="gmail_extra"><span style="white-space:pre-wrap">        </span>[:m|</div><div class="gmail_extra"><span style="white-space:pre-wrap">        </span>self mapFor: m</div><div class="gmail_extra"><span style="white-space:pre-wrap">                </span>performAllMapEntriesUntil:</div><div class="gmail_extra"><span style="white-space:pre-wrap">                </span>#withAnnotation:pc:evaluate:</div><div class="gmail_extra"><span style="white-space:pre-wrap">                </span>arg: [:annotation :pc| dynamicFrequencies add: annotation. false]].</div><div class="gmail_extra">dynamicFrequencies sortedCounts collect:</div><div class="gmail_extra"><span style="white-space:pre-wrap">        </span>[:assoc|</div><div class="gmail_extra"><span style="white-space:pre-wrap">        </span>assoc key -&gt; (self class annotationConstantNames at: assoc value + 1)]</div><div class="gmail_extra"> {5867-&gt;#IsSendCall . 3139-&gt;#HasBytecodePC . 2700-&gt;#IsDisplacementX2N . 2307-&gt;#IsRelativeCall . 1568-&gt;#IsAbsPCReference . 1120-&gt;#IsObjectReference}</div><br clear="all"><div>Looks like IsDisplacement is surplus to requirements.<span class=""><font color="#888888"><br>-- </font></span></div><span class=""><font color="#888888"><div>best,<div>Eliot</div></div>
</font></span></div></div>
</blockquote></div><div class="gmail_extra"><br></div>and this tells us that using alignment to distinguish super sends is not worth it; super sends are just too rare, 0.65% of all sends in one particular run of a Squeak image:</div><div class="gmail_extra"><br></div><div class="gmail_extra"><div class="gmail_extra">| dynamicFrequencies nSends nSuperSends nLinked nUnlinked |</div><div class="gmail_extra">dynamicFrequencies := Bag new.</div><div class="gmail_extra">nSends := nSuperSends := nLinked := nUnlinked := 0.</div><div class="gmail_extra">methodZone methodsDo:</div><div class="gmail_extra"><span class="" style="white-space:pre">        </span>[:m|</div><div class="gmail_extra"><span class="" style="white-space:pre">        </span>self mapFor: m</div><div class="gmail_extra"><span class="" style="white-space:pre">                </span>performAllMapEntriesUntil:</div><div class="gmail_extra"><span class="" style="white-space:pre">                </span>#withAnnotation:pc:evaluate:</div><div class="gmail_extra"><span class="" style="white-space:pre">                </span>arg: [:annotation :mcpc| | entryPoint |</div><div class="gmail_extra"><span class="" style="white-space:pre">                        </span>dynamicFrequencies add: annotation.</div><div class="gmail_extra"><span class="" style="white-space:pre">                        </span>annotation &gt;= IsSendCall ifTrue:</div><div class="gmail_extra"><span class="" style="white-space:pre">                                </span>[entryPoint := backEnd callTargetFromReturnAddress: mcpc.</div><div class="gmail_extra"><span class="" style="white-space:pre">                                </span> entryPoint &gt;= methodZoneBase</div><div class="gmail_extra"><span class="" style="white-space:pre">                                        </span>ifTrue:</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                </span>[nLinked := nLinked + 1.</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                </span> self targetMethodAndSendTableFor: entryPoint into:</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                        </span>[:table :target|</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                        </span> table == superSendTrampolines</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                                </span>ifTrue: [nSuperSends := nSuperSends + 1]</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                                </span>ifFalse: [nSends := nSends + 1]]]</div><div class="gmail_extra"><span class="" style="white-space:pre">                                        </span>ifFalse:</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                </span>[nUnlinked := nUnlinked + 1.</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                </span> entryPoint &gt;= (superSendTrampolines at: 0)</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                        </span>ifTrue: [nSuperSends := nSuperSends + 1]</div><div class="gmail_extra"><span class="" style="white-space:pre">                                                        </span>ifFalse: [nSends := nSends + 1]]].</div><div class="gmail_extra"><span class="" style="white-space:pre">                        </span>false]].</div><div class="gmail_extra">{ dynamicFrequencies sortedCounts collect:</div><div class="gmail_extra"><span class="" style="white-space:pre">        </span>[:assoc|</div><div class="gmail_extra"><span class="" style="white-space:pre">        </span>assoc key -&gt; (self class annotationConstantNames at: assoc value + 1)].</div><div class="gmail_extra">nSends. nSuperSends. nLinked. nUnlinked } {{5867-&gt;#IsSendCall . 3139-&gt;#HasBytecodePC . 2700-&gt;#IsDisplacementX2N . 2307-&gt;#IsRelativeCall . 1568-&gt;#IsAbsPCReference . 1120-&gt;#IsObjectReference} . 5829 . 38 . 3065 . 2802}</div><br clear="all"><div><br></div>-- <br><div class="gmail_signature">best,<div>Eliot</div></div>
</div></div>