Hi Guillermo,<br><br><div class="gmail_quote">On Tue, Apr 16, 2013 at 8:27 AM, Guillermo Polito <span dir="ltr">&lt;<a href="mailto:guillermopolito@gmail.com" target="_blank">guillermopolito@gmail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <br><div dir="ltr"><div>Hi! I&#39;m looking at some code from StackInterpreter, and the given piece of code raised a question I cannot fully answer:</div>
<div><br></div><div>longUnconditionalJump</div><div><span style="white-space:pre-wrap">        </span>| offset |</div>
<div><span style="white-space:pre-wrap">        </span>offset := (((currentBytecode bitAnd: 7) - 4) * 256) + self fetchByte.</div><div><span style="white-space:pre-wrap">        </span>localIP := localIP + offset.</div><div><span style="white-space:pre-wrap">        </span>(offset &lt; 0 &quot;backward jump means we&#39;re in a loop; check for possible interrupts&quot;</div>

<div><span style="white-space:pre-wrap">        </span> and: [<b>localSP &lt; stackLimit</b>]) ifTrue:</div><div><span style="white-space:pre-wrap">                </span>[self externalizeIPandSP.</div><div><span style="white-space:pre-wrap">                </span> self checkForEventsMayContextSwitch: true.</div>

<div><span style="white-space:pre-wrap">                </span> self browserPluginReturnIfNeeded.</div><div><span style="white-space:pre-wrap">                </span> self internalizeIPandSP].</div><div><span style="white-space:pre-wrap">        </span>self fetchNextBytecode</div>

<div><br></div><div>What does the (localSP &lt; stackLimit) condition stand for? What is its intention when deciding to make (or not) a context switch?</div></div></blockquote><div><br></div><div>The Cog and Stack VMs steal a technique from Peter Deutsch&#39;s PS and HPS VMs which combines the stack page overflow check on method entry with the check for events.  Internally these VMs run Smalltalk on a small set of stack pages (this is to do with going fast by using a call-instruction-based inline cache, and needing to implement contexts, mapping stack frames to contexts as needed).  Periodically the VM needs to break out of executing Smalltalk and check for events (the VMs heartbeat)., and this is done by setting the stackLimit to the highest possible value ((all ones) so that all stack overflow checks fail, and on the next method entry or backward jump the VM will check for stack overflow.  If there really is a stack overflow then it is dealt with, but if the stack limit has been changed to all ones then the  M checks for events.</div>
<div><br></div><div>This is explained here: <a href="http://www.mirandabanda.org/cogblog/2009/01/14/under-cover-contexts-and-the-big-frame-up/">http://www.mirandabanda.org/cogblog/2009/01/14/under-cover-contexts-and-the-big-frame-up/</a></div>
<div><br></div><div><span class="Apple-style-span" style="color:rgb(34,34,34);font-family:arial,helvetica,sans-serif;font-size:14px;line-height:21px"><span style="color:rgb(0,0,0)">&quot;We have a linked list of StackPage objects, one for each page, that we use to keep stack pages in order of usage, along with free pages, referenced by a variable called the mostRecentlyUsedPage. Each StackPage keeps track of whether a stack page is in use (baseFP is non-null) and what part of the page is in use (from the first slot through to the headSP) and what the frames are in the page (the list from headFP chained through caller saved fp to the baseFP). The interpreter’s current stack page is called stackPage. On stack switch we load stackLimit from stackPage’s stackLimit. Peter cleverly realised that one can use the stackLimit check to cause the VM to break out of execution to process input events. The VM is set up to respond to potential input with an interrupt handler that sets the stackLimit to all ones (the highest possible address) so that the next stack overflow check will fail. We also check for stack overflow on backward branch so that we can break out of infinite loops:<br>
</span><br><em>StackInterpreter methods for jump bytecodes</em><span style="color:rgb(0,0,0)"><br></span><strong>longUnconditionalJump</strong><span style="color:rgb(0,0,0)"><br>        </span><span style="color:rgb(128,128,128)">|</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(64,64,64)">offset</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(128,128,128)">|</span><span style="color:rgb(0,0,0)"><br>
        </span><span style="color:rgb(64,64,64)">offset</span><span style="color:rgb(0,0,0)"> </span><strong>:=</strong><span style="color:rgb(0,0,0)"> (</span><span style="color:rgb(0,128,0)">(</span><span style="color:rgb(128,0,128)">(</span><span style="color:rgb(0,0,0)">currentBytecode </span><span style="color:rgb(0,0,128)">bitAnd:</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(128,0,0)">7</span><span style="color:rgb(128,0,128)">)</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">-</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(128,0,0)">4</span><span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">*</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(128,0,0)">256</span><span style="color:rgb(0,0,0)">) </span><span style="color:rgb(0,0,128)">+</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(128,0,0)">self</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">fetchByte</span><span style="color:rgb(0,0,0)">.<br>
        localIP </span><strong>:=</strong><span style="color:rgb(0,0,0)"> localIP </span><span style="color:rgb(0,0,128)">+</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(64,64,64)">offset</span><span style="color:rgb(0,0,0)">.<br>
        (</span><span style="color:rgb(64,64,64)">offset</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">&lt;</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(128,0,0)">0</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,128,128)">“backward jump means we’re in a loop; check for possible interrupts”</span><span style="color:rgb(0,0,0)"><br>
         </span><span style="color:rgb(0,0,128)">and:</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,128,0)">[</span><span style="color:rgb(0,0,0)">localSP </span><span style="color:rgb(0,0,128)">&lt;</span><span style="color:rgb(0,0,0)"> stackLimit</span><span style="color:rgb(0,128,0)">]</span><span style="color:rgb(0,0,0)">) </span><span style="color:rgb(0,0,128)">ifTrue:</span><span style="color:rgb(0,0,0)"><br>
                        [</span><span style="color:rgb(128,0,0)">self</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">externalizeIPandSP</span><span style="color:rgb(0,0,0)">.<br>                         </span><span style="color:rgb(128,0,0)">self</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">checkForEventsMayContextSwitch:</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(128,0,0)">true</span><span style="color:rgb(0,0,0)">.<br>
                         </span><span style="color:rgb(128,0,0)">self</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">browserPluginReturnIfNeeded</span><span style="color:rgb(0,0,0)">.<br>                         </span><span style="color:rgb(128,0,0)">self</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">internalizeIPandSP</span><span style="color:rgb(0,0,0)">].<br>
        </span><span style="color:rgb(128,0,0)">self</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(0,0,128)">fetchNextBytecode</span></span></div><div>&quot;</div><div><br></div><div>-- </div></div>cheers,<div>
Eliot</div>