<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Apr 16, 2013 at 8:12 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"> <br>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:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style: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). </div>

</div></blockquote><div><br></div><div>Yeap, that I understood (given my limitations, haha) from your blog :).</div><div> </div><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 class="gmail_quote"><div>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)</div>

</div></blockquote><div><br></div><div>Then, my question is: When does the VM decide it needs to do a context switch? In other words, when does it decide to put the stack limit to 0xffffffff ?</div><div><br></div>
<div>My case (triggering the question) is the following:</div><div><br></div><div>I&#39;m experimenting on switching the special objects array with different processes, and therefore debugging the process switching.</div>
<div><br></div><div>- I resume a process with the following code:</div>
<div><br></div><div><div> | finished times | </div><div><span style="white-space:pre-wrap"> </span>times := 0.</div><div><span style="white-space:pre-wrap"> </span>[ times := times + 1.</div><div><span style="white-space:pre-wrap">   </span>times &lt; 30000 ] whileTrue.</div>

<div><span style="white-space:pre-wrap"> </span>finished := true.</div><div><br></div></div><div style>with an empty processor</div><div><br></div><div>- a stack page is created (or taken, not sure about the exact terminology here) for the process cause it was not married</div>

<div>- it enters #checkForEventsMayContextSwitch: after long run (lets say ~16000 loops), and gets preempted (and I move to another special objects array with lots of processes)</div><div>- then, every time I resume it, it enters #checkForEventsMayContextSwitch: after looping only one time<br>
</div><div><br></div><div>I know that I&#39;m playing with a non-standard vm, but any clue that helps me to understand why the difference is appreciated :).</div><div><br></div><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 class="gmail_quote"><div> 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/" target="_blank">http://www.mirandabanda.org/cogblog/2009/01/14/under-cover-contexts-and-the-big-frame-up/</a></div>


<div><br></div><div><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></blockquote><div>

<br></div><div><div>Another silly question. The blog says:</div><div><br></div><div>&quot;<span style="font-family:arial,helvetica,sans-serif;font-size:14px;line-height:21px">But a naive implementation has to allocate a context on each send, move the receiver and arguments from the stack of the caller context to that of the callee, and assign the callee’s sender with the caller. For essentially every return the garbage collector eventually has to reclaim, and every return has to nil the sender and instruction pointer fields of, the context being returned from.&quot;</span></div>

<div><span style="font-family:arial,helvetica,sans-serif;font-size:14px;line-height:21px"><br></span></div><div><span style="line-height:21px"><font face="arial, helvetica, sans-serif">When talking about the cost of moving the receiver and arguments to the new context, don&#39;t you have to push all that in the stack too? Or the values pushed in the stack by the sender are the ones used by the new activation (thus pushing only once)? (that&#39;s what I kind of understand from the post, but better double check :))</font></span></div>

</div><div><span style="line-height:21px"><font face="arial, helvetica, sans-serif"><br></font></span></div><div><span style="line-height:21px"><font face="arial, helvetica, sans-serif">Thanks!</font></span></div><div>
<span style="line-height:21px"><font face="arial, helvetica, sans-serif">Guille</font></span></div><div> </div><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 class="gmail_quote"><div></div><div>-- </div></div>cheers,<div>
Eliot</div>
<br></blockquote></div><br></div></div>