<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, May 20, 2016 at 7:51 PM, Ben Coman <span dir="ltr">&lt;<a href="mailto:btc@openinworld.com" target="_blank">btc@openinworld.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div class=""><div class="h5"><br>
On Fri, May 20, 2016 at 9:25 PM, Clément Bera &lt;<a href="mailto:bera.clement@gmail.com">bera.clement@gmail.com</a>&gt; wrote:<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt; On Thu, May 19, 2016 at 3:42 PM, Ben Coman &lt;<a href="mailto:btc@openinworld.com">btc@openinworld.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; The hierarchy goes<br>
&gt;&gt;   VMClass<br>
&gt;&gt;      InterpreterPrimitives<br>
&gt;&gt;         StackIntepreter<br>
&gt;&gt;           StackIntepreterPrimitives<br>
&gt;&gt;              CoInterpreter<br>
&gt;&gt;                CoInterpreterPrimitives<br>
&gt;&gt;<br>
&gt;&gt; from which a tick / tock (XXInterpreter / XXInterpreterPrimitives)<br>
&gt;&gt; pattern is apparent,<br>
&gt;&gt; and I wonder why Interpreter is missing above InterpreterPrimitives<br>
&gt;&gt; sitting off to the side.  I guess it is something to do with<br>
&gt;&gt; InterpreterPrimitives composing objectMemory as an instance variable<br>
&gt;&gt; rather than inheriting from ObjectMemory as Interpeter does?<br>
&gt;<br>
&gt;<br>
&gt; I think this is exactly that.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; The reason I ask is that I&#39;m trying a new approach to the OwnedLock primitives<br>
&gt;&gt; where if waitAcquire primitive sleeps, when the process wakes up it<br>
&gt;&gt; retries the primitive.<br>
&gt;&gt; So effectively the process sleeps at the top of the waitAquire rather<br>
&gt;&gt; than the bottom,<br>
&gt;&gt; and the process truly cannot proceed past that point until it gains<br>
&gt;&gt; the lock. I have this working if StackInterpreterPrimitives holds the<br>
&gt;&gt; primitive, but if I move the primitive to InterpreterPrimitives,<br>
&gt;&gt; instructionPointer is unknown.<br>
&gt;&gt;<br>
&gt;<br>
&gt; In general, you implement in InterpreterPrimitives the primitives that would work with the Interpreter, and in StackInterpreterPrimitives the ones specific to the StackInterpreter. If you have a bug in InterpreterPrimitives, it&#39;s likely to be specific to the StackInterpreter.<br>
&gt;<br>
&gt; In the future the Cog branch may merge with the trunk, hence Interpreter will be back in the hierarchy.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; P.S. For the curious, here is the proof of concept I tried.  A single<br>
&gt;&gt; call to the primitive counts up to four by backing up the<br>
&gt;&gt; instructionPointer such that the primitive is executed again, until<br>
&gt;&gt; the exit condition of four is reached.<br>
&gt;&gt;<br>
&gt;&gt; (Note the use of Semaphore and ExcessSignalsIndex is not significant,<br>
&gt;&gt; just an expedient template I was familiar with.)<br>
&gt;&gt;<br>
&gt;&gt; # VM SIDE...<br>
&gt;&gt;<br>
&gt;&gt; StackInterpreterPrimitives &gt;&gt; primitiveRetryExperiment<br>
&gt;&gt;     | excessSignals stackTop |<br>
&gt;&gt;     stackTop := self stackTop.<br>
&gt;&gt;     excessSignals := objectMemory fetchInteger: ExcessSignalsIndex<br>
&gt;&gt; ofObject: stackTop.<br>
&gt;&gt;     excessSignals := excessSignals + 1.<br>
&gt;&gt;     objectMemory storeInteger: ExcessSignalsIndex<br>
&gt;&gt;         ofObject: stackTop<br>
&gt;&gt;         withValue: excessSignals.<br>
&gt;&gt;     [ excessSignals &gt; 3 ] ifFalse: [ instructionPointer :=<br>
&gt;&gt; instructionPointer - 1 ].<br>
&gt;&gt;<br>
&gt;&gt; StackInterpreter class &gt;&gt; initializePrimitiveTable<br>
&gt;&gt;     (234 primitiveRetryExperiment)<br>
&gt;&gt;<br>
&gt;<br>
&gt; ... Why instructionPointer - 1 ?<br>
<br>
</div></div>A random experiment before moving on to -2, -3 and -4.   Obviously I<br>
don&#39;t know enough yet to have properly judged its impact.  Just poking<br>
it with a stick to see what pops out, and following that old adage<br>
that if you need something to be true, &quot;assume it&quot; until you learn<br>
otherwise.  And whadayaknow..., it worked for the StackInterpreter.<br>
And I&#39;ve since learnt its not so easy for the JIT.<br>
<span class=""><br>
&gt; It works if the send is encoded in a single byte as by chance is the case in your example, else your interpretation get misaligned, which is a complete nonsense (unless you&#39;re working with a Smalltalk-78 VM ;-) ). Going backward in the instructions is not that trivial, you need a scanner to find the previous pc.<br>
<br>
</span>I thought *maybe* that since the layout of the receiver is &quot;known&quot; (to<br>
be an OwnedLock) the previous pc could be assumed at a known distance<br>
up the stack - but maybe that is bad practice and trouble if the<br>
layout changes for anyone subclassing OwnedLock.<br>
<span class=""><br></span></blockquote><div><br></div><div>I don&#39; really understand that known layout of the receiver thing. </div><div><br></div><div>The problem is with the encoding of sends in the bytecode. They are encoded in different number of bytes to lower the memory footprint.</div><div><br></div><div>For example, in Pharo, in this method:</div><div>foo</div><div>    <span style="font-family:monospace,monospace">PrimExp new primRetryExperiment excessSignals</span></div><div><span style="font-family:monospace,monospace"><br></span></div><div><span style="font-family:monospace,monospace">=&gt; </span><font face="monospace, monospace">27 &lt;D1&gt; send: primRetryExperiment</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="arial, helvetica, sans-serif">the send to </font><span style="font-family:monospace,monospace">primRetryExperiment</span><span style="font-family:arial,helvetica,sans-serif"> is encoded in a single byte.</span></div><div><font face="monospace, monospace"><br></font></div><div>But in this method:</div><div><div><font face="monospace, monospace">foo</font></div><div><font face="monospace, monospace"><span style="white-space:pre">    </span>self foo1 foo2 foo3 foo4 foo5 foo6 foo7 foo8 </font></div><div><font face="monospace, monospace">    self foo9 foo10 foo11 foo12 foo13 foo14 foo15 foo16.</font></div><div><font face="monospace, monospace">    PrimExp new primRetryExperiment excessSignals</font></div></div><div><span style="font-family:monospace,monospace"><br></span></div><div><font face="monospace, monospace">=&gt; 109 &lt;83 11&gt; send: primRetryExperiment</font><br></div><div><font face="monospace, monospace"><br></font></div><div><font face="arial, helvetica, sans-serif">The same send is encoded in 2 bytes.</font></div><div><font face="arial, helvetica, sans-serif"><br></font></div><div>So, after the send, in the primitive code, you need the instruction pointer to go back by 1 or 2 bytes to repeat the send. But you don&#39;t know by how many bytes. <span style="font-family:arial,helvetica,sans-serif">There is no easy way to guess if it&#39;s 1 or 2 (or something else, there are other cases I omitted).</span></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><span class="">
&gt; See #skipBackBeforeJump for example, which goes backward 1 instruction in the image side. You need to implement something similar in the interpreter if you want to do that... but you don&#39;t.<br>
<br>
</span>I&#39;ll take a look just for interest, but point taken.<br>
<span class=""><br>
&gt; Although going back one instruction is very funny, it won&#39;t work with the JIT, unless you do something completely evil, crazy and hackish.<br>
<br>
</span>That was the advice I was looking for.  I don&#39;t want to be hackish ;)<br>
 At least not in the final result.<br>
<span class=""><br>
&gt; Most likely you want in fact to implement your primitive with a while loop instead, so you don&#39;t need that ip modification hack. Why didn&#39;t you do a while loop in the first place ?<br>
<br>
</span>A loop in the Image would work, but I&#39;m attempting to keep it in the<br>
VM.  IIUC a loop won&#39;t work in the VM because the primitive sleeps and<br>
changes context if the lock is held by someone else.<br></blockquote><div><br></div><div>hum. If I change your example to:</div><div><br></div><font face="monospace, monospace"><span style="color:rgb(80,0,80)">StackInterpreterPrimitives &gt;&gt; primitiveRetryExperiment</span><br style="color:rgb(80,0,80)"><span style="color:rgb(80,0,80)">     | excessSignals stackTop |</span><br style="color:rgb(80,0,80)"><span style="color:rgb(80,0,80)">     stackTop := self stackTop.</span><br style="color:rgb(80,0,80)"><span style="color:rgb(80,0,80)">     excessSignals := objectMemory fetchInteger: ExcessSignalsIndex</span><span style="color:rgb(80,0,80)"> ofObject: stackTop.</span><br style="color:rgb(80,0,80)"><span style="color:rgb(80,0,80)">     [ </span><span style="color:rgb(80,0,80)">excessSignals &gt; 3 ] whileFalse: [</span></font></div><div class="gmail_quote"><font face="monospace, monospace"><span style="color:rgb(80,0,80)">         excessSignals := excessSignals + 1.</span><br style="color:rgb(80,0,80)"><span style="color:rgb(80,0,80)">         objectMemory storeInteger: ExcessSignalsIndex</span><br style="color:rgb(80,0,80)"><span style="color:rgb(80,0,80)">             ofObject: stackTop</span><br style="color:rgb(80,0,80)"><span style="color:rgb(80,0,80)">             withValue: excessSignals</span><span style="color:rgb(80,0,80)"> ].</span> </font></div><div class="gmail_quote"><br></div><div class="gmail_quote">It&#39;s exactly equivalent to what you wrote, isn&#39;t it ? There is no process switch - context switch - in both cases in the loop, isn&#39;t it ? Or maybe I am missing something ?</div><div class="gmail_quote"><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<span class=""><br>
&gt; Primitive calls are not interrupt points anyway, it would be exactly the same behavior, wouldn&#39;t it ?<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; # IMAGE SIDE...<br>
&gt;&gt;<br>
&gt;&gt; Semaphore subclass: #PrimExp<br>
&gt;&gt;     instanceVariableNames: &#39;&#39;<br>
&gt;&gt;     classVariableNames: &#39;&#39;<br>
&gt;&gt;     package: &#39;0PrimitiveRetryExperiment&#39;<br>
&gt;&gt;<br>
&gt;&gt; PrimExp &gt;&gt; initialize<br>
&gt;&gt;     excessSignals := 1.<br>
&gt;&gt;<br>
&gt;&gt; PrimExp &gt;&gt; primRetryExperiment<br>
&gt;&gt;     &lt;primitive: 234&gt;<br>
&gt;&gt;<br>
&gt;&gt; PrimExp &gt;&gt; excessSignals<br>
&gt;&gt;     ^ excessSignals<br>
&gt;&gt;<br>
&gt;&gt; # TEST CASE...<br>
&gt;&gt;<br>
&gt;&gt; PrimExp new primRetryExperiment excessSignals<br>
&gt;&gt;     --&gt; 4<br>
&gt;&gt;<br>
&gt;&gt; I&#39;ve only done this with the Stack VM so far.  I&#39;ll report further<br>
&gt;&gt; when I try it with Cog.<br>
<br>
</span>So I found the approach doesn&#39;t work with Cog.<br>
cheers -ben<br>
<div class=""><div class="h5"><br>
&gt;<br>
&gt; It&#39;s nice to see people trying to hack the VM :-). I&#39;ll try to answer your other questions.<br>
</div></div></blockquote></div><br></div></div>