<div dir="ltr">Hi Ben, Hi Denis, Hi Clément,<div class="gmail_extra"><br><div class="gmail_quote">On Fri, May 20, 2016 at 7:52 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-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><br>
On Sat, May 21, 2016 at 4:36 AM, Clément Bera &lt;<a href="mailto:bera.clement@gmail.com">bera.clement@gmail.com</a>&gt; wrote:<br>
<span class="">&gt; On Fri, May 20, 2016 at 7:51 PM, Ben Coman &lt;<a href="mailto:btc@openinworld.com">btc@openinworld.com</a>&gt; wrote:<br>
&gt;&gt; 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;&gt; &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>
<br>
</span><div><div class="h5">&gt;&gt; &gt;&gt; P.S. For the curious, here is the proof of concept I tried.  A single<br>
&gt;&gt; &gt;&gt; call to the primitive counts up to four by backing up the<br>
&gt;&gt; &gt;&gt; instructionPointer such that the primitive is executed again, until<br>
&gt;&gt; &gt;&gt; the exit condition of four is reached.<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; (Note the use of Semaphore and ExcessSignalsIndex is not significant,<br>
&gt;&gt; &gt;&gt; just an expedient template I was familiar with.)<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; # VM SIDE...<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; StackInterpreterPrimitives &gt;&gt; primitiveRetryExperiment<br>
&gt;&gt; &gt;&gt;     | excessSignals stackTop |<br>
&gt;&gt; &gt;&gt;     stackTop := self stackTop.<br>
&gt;&gt; &gt;&gt;     excessSignals := objectMemory fetchInteger: ExcessSignalsIndex<br>
&gt;&gt; &gt;&gt; ofObject: stackTop.<br>
&gt;&gt; &gt;&gt;     excessSignals := excessSignals + 1.<br>
&gt;&gt; &gt;&gt;     objectMemory storeInteger: ExcessSignalsIndex<br>
&gt;&gt; &gt;&gt;         ofObject: stackTop<br>
&gt;&gt; &gt;&gt;         withValue: excessSignals.<br>
&gt;&gt; &gt;&gt;     [ excessSignals &gt; 3 ] ifFalse: [ instructionPointer :=<br>
&gt;&gt; &gt;&gt; instructionPointer - 1 ].<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; StackInterpreter class &gt;&gt; initializePrimitiveTable<br>
&gt;&gt; &gt;&gt;     (234 primitiveRetryExperiment)<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; ... Why instructionPointer - 1 ?<br>
&gt;&gt;<br>
&gt;&gt; A random experiment before moving on to -2, -3 and -4.   Obviously I<br>
&gt;&gt; don&#39;t know enough yet to have properly judged its impact.  Just poking<br>
&gt;&gt; it with a stick to see what pops out, and following that old adage<br>
&gt;&gt; that if you need something to be true, &quot;assume it&quot; until you learn<br>
&gt;&gt; otherwise.  And whadayaknow..., it worked for the StackInterpreter.<br>
&gt;&gt; And I&#39;ve since learnt its not so easy for the JIT.<br>
&gt;&gt;<br>
&gt;&gt; &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>
&gt;&gt;<br>
&gt;&gt; I thought *maybe* that since the layout of the receiver is &quot;known&quot; (to<br>
&gt;&gt; be an OwnedLock) the previous pc could be assumed at a known distance<br>
&gt;&gt; up the stack - but maybe that is bad practice and trouble if the<br>
&gt;&gt; layout changes for anyone subclassing OwnedLock.<br>
&gt;<br>
</div></div>&gt; I don&#39; really understand that known layout of the receiver thing.<br>
<br>
Just my limited understanding anf naive assumption.  The course I took<br>
on compilers was 20 years ago. You counter example below helps...<br>
<br>
<br>
&gt; The problem is with the encoding of sends in the bytecode. They are encoded in different number of bytes to lower the memory footprint.<br>
&gt;<br>
&gt; For example, in Pharo, in this method:<br>
&gt; foo<br>
&gt;     PrimExp new primRetryExperiment excessSignals<br>
&gt;<br>
&gt; =&gt; 27 &lt;D1&gt; send: primRetryExperiment<br>
&gt;<br>
&gt; the send to primRetryExperiment is encoded in a single byte.<br>
&gt;<br>
&gt; But in this method:<br>
&gt; foo<br>
&gt;   self foo1 foo2 foo3 foo4 foo5 foo6 foo7 foo8<br>
&gt;     self foo9 foo10 foo11 foo12 foo13 foo14 foo15 foo16.<br>
&gt;     PrimExp new primRetryExperiment excessSignals<br>
&gt;<br>
&gt; =&gt; 109 &lt;83 11&gt; send: primRetryExperiment<br>
&gt;<br>
&gt; The same send is encoded in 2 bytes.<br>
<br>
&gt; 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. There is no easy way to guess if it&#39;s 1 or 2 (or something else, there are other cases I omitted).<br>
<br>
<br>
Okay. That helps me understand of my task better.<br>
<span class=""><br>
&gt;&gt; &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>
&gt;&gt;<br>
&gt;&gt; I&#39;ll take a look just for interest, but point taken.<br>
&gt;&gt;<br>
&gt;&gt; &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>
&gt;&gt;<br>
&gt;&gt; That was the advice I was looking for.  I don&#39;t want to be hackish ;)<br>
&gt;&gt;  At least not in the final result.<br>
&gt;&gt;<br>
&gt;&gt; &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>
&gt;&gt;<br>
&gt;&gt; A loop in the Image would work, but I&#39;m attempting to keep it in the<br>
&gt;&gt; VM.  IIUC a loop won&#39;t work in the VM because the primitive sleeps and<br>
&gt;&gt; changes context if the lock is held by someone else.<br>
&gt;<br>
&gt;<br>
</span>&gt; hum. If I change your example to:<br>
<span class="">&gt;<br>
&gt; StackInterpreterPrimitives &gt;&gt; primitiveRetryExperiment<br>
&gt;      | excessSignals stackTop |<br>
&gt;      stackTop := self stackTop.<br>
&gt;      excessSignals := objectMemory fetchInteger: ExcessSignalsIndex ofObject: stackTop.<br>
</span>&gt;      [ excessSignals &gt; 3 ] whileFalse: [<br>
<span class="">&gt;          excessSignals := excessSignals + 1.<br>
&gt;          objectMemory storeInteger: ExcessSignalsIndex<br>
&gt;              ofObject: stackTop<br>
</span>&gt;              withValue: excessSignals ].<br>
&gt;<br>
&gt; 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 ?<br>
<br>
Apologies for mis-leading the discussion. The missing bit is, the<br>
above isn&#39;t my actually requirement.  Its only an experiment of the<br>
effect of modifying the instruction pointer. My real use case is for<br>
the OwnedLock primitives I&#39;m introducing [1], which at the end of<br>
primitiveOwnedLockWaitAcquire.<br>
<br>
    self transferTo: self wakeHighestPriority from: CSOwnedLockWaitAcquire.<br>
    self forProcessPrimitiveReturnToExecutivePostContextSwitch: inInterpreter.<br>
<br>
That code works well, except for one corner case identified by Dennis<br>
where after primitiveOwnedLockRelease hands the lock to a waiting<br>
process, that process could be terminated before waking up. </blockquote><div><br></div><div>There is a better way of solving this, and that is to use a pragma to identify a method that contains such a suspension point, and have the process terminate code look for the pragma and act accordingly.  For example, the pragma could have a terminate action, sent to the receiver with the context as argument, e.g.</div><div><br></div><div>Mutex&gt;&gt;critical: mutuallyExcludedBlock<br>    &lt;onTerminate: #ensureMutexUnlockedInCritical:&gt;</div><div>    ^lock waitAcquire<br></div>        ifNil: mutuallyExcludedBlock<br>        ifNotNil:[ mutuallyExcludedBlock ensure: [lock release] ]</div><div class="gmail_quote"><br></div><div class="gmail_quote">(and here I&#39;m guessing...)</div><div class="gmail_quote"><br></div><div class="gmail_quote">Mutex&gt;&gt; ensureMutexUnlockedInCritical: aContext</div><div class="gmail_quote">    &quot;long-winded comment explaining the corner case, referencing tests, etc, etc and how it is solved on terminate buy this method&quot;</div><div class="gmail_quote">    (aContext pc = aContext initialPC</div><div class="gmail_quote">     and: [self inTheCorner]) ifTrue:</div><div class="gmail_quote">        [self doTheRightThingTM]</div><div class="gmail_quote"><br></div><div class="gmail_quote">So on terminate the stack is walked (it is anyway) looking for unwinds or onTerminate: markers.  Any onTerminate: markers are evaluated, and the corner case is solved.  The pragma approach also allows for visibility in the code.</div><div class="gmail_quote"><br></div><div class="gmail_quote"><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"> Doing<br>
that in primitiveOwnedLockRelease is required because when<br>
primitiveOwnedLockWaitAcquire goes to sleep, you&#39;ve already past its<br>
code that acquires the lock.<br>
<br>
Mutex&gt;&gt;critical: mutuallyExcludedBlock<br>
    ^[  lock waitAcquire<br>
             ifNil: mutuallyExcludedBlock<br>
             ifNotNil: mutuallyExcludedBlock<br>
      ] ensure: [lock release].<br>
<br>
instead of the faster...<br>
Mutex&gt;&gt;critical: mutuallyExcludedBlock<br>
    ^lock waitAcquire<br>
        ifNil: mutuallyExcludedBlock<br>
        ifNotNil:[ mutuallyExcludedBlock ensure: [lock release] ].<br>
<br>
I&#39;d heard about Eliot &quot;retrying primitives&quot; for forwarding failures<br>
and considered a solution might be for primitiveOwnedLockWaitAcquire<br>
to be re-executed when its process woke up.  So the lock is only<br>
acquired after the process wakes up, rather than being handed to it<br>
while it was asleep.  Conceptually the process sleeps at the top of<br>
the primitive rather than the bottom.<br>
<br>
I found what Eliot does...<br>
     dispatchFunctionPointer(primitiveFunctionPointer);<br>
      /* begin maybeRetryFailureDueToForwarding */<br>
      if (GIV(primFailCode)<br>
       &amp;&amp; (checkForAndFollowForwardedPrimitiveState())) {<br>
              /* begin initPrimCall */<br>
              GIV(primFailCode) = 0;<br>
              dispatchFunctionPointer(primitiveFunctionPointer);<br>
      }<br>
<br>
but I guess that won&#39;t work when switching processes.  So having<br>
caught the idea for primitive retry, I went looking for another way<br>
that worked across a process switch, and learn a bit more about the VM<br>
in the process.   Hence my experiment to naively decrement the<br>
instruction pointer before switching context.<br>
<br>
[1] <a href="http://forum.world.st/OwnedLock-primitives-request-for-review-td4886130.html" rel="noreferrer" target="_blank">http://forum.world.st/OwnedLock-primitives-request-for-review-td4886130.html</a><br>
<br>
cheers -ben<br>
<div class=""><div class="h5"><br>
&gt;&gt;<br>
&gt;&gt; &gt; Primitive calls are not interrupt points anyway, it would be exactly the same behavior, wouldn&#39;t it ?<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; # IMAGE SIDE...<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; Semaphore subclass: #PrimExp<br>
&gt;&gt; &gt;&gt;     instanceVariableNames: &#39;&#39;<br>
&gt;&gt; &gt;&gt;     classVariableNames: &#39;&#39;<br>
&gt;&gt; &gt;&gt;     package: &#39;0PrimitiveRetryExperiment&#39;<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; PrimExp &gt;&gt; initialize<br>
&gt;&gt; &gt;&gt;     excessSignals := 1.<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; PrimExp &gt;&gt; primRetryExperiment<br>
&gt;&gt; &gt;&gt;     &lt;primitive: 234&gt;<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; PrimExp &gt;&gt; excessSignals<br>
&gt;&gt; &gt;&gt;     ^ excessSignals<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; # TEST CASE...<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; PrimExp new primRetryExperiment excessSignals<br>
&gt;&gt; &gt;&gt;     --&gt; 4<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; I&#39;ve only done this with the Stack VM so far.  I&#39;ll report further<br>
&gt;&gt; &gt;&gt; when I try it with Cog.<br>
&gt;&gt;<br>
&gt;&gt; So I found the approach doesn&#39;t work with Cog.<br>
&gt;&gt; cheers -ben<br>
&gt;&gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &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><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>
</div></div>