<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Wed, 29 Aug 2018 at 11:08, Eliot Miranda <<a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a>> wrote:</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><br></div><div>All other primitives are handled by slowPrimitiveResponse.  This requires clearing primErrorCode and calling a function implementing the primitive and then testing primErrorCode before either continuing or building an activation for the failing primitive. There is another important task of internalExecuteNewMethod, which is to store the "internal" frame and stack pointers (localFP & localSP) into the global interpreter frame and stack pointers (framePointer and stackPointer) before invoking and then restoring localFP & localSP from framePointer and stackPointer after having invoked slowPrimitiveResponse.  In the Back-to-the-Future (BTTF) VMs (the original Squeak VM and the Stack and Cog VMs) primitives access their receiver and arguments through framePointer and stackPointer.  But these, being global, are slow and without compiler-specific hacks cannot be placed in registers.  </div></div></div></blockquote><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>The Slang translator and the interpreter code collaborate to inline much of the interpreter, including every method beginning with internal, into the interpret routine in which localFP localSP and localIP are declared, hence allowing a C compiler to assign these variables to registers.  </div></div></div></blockquote><div><br></div><div>Ahhh. Maybe I finally get what "internal" means. IIUC, its code gets generated internal to C interpret() function,</div><div>as I can see searching for "<span style="color:rgb(0,0,0);white-space:pre-wrap">internalExecuteNewMethod" </span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">in... </span><font color="#000000"><span style="white-space:pre-wrap"><a href="https://raw.githubusercontent.com/OpenSmalltalk/opensmalltalk-vm/Cog/spurstacksrc/vm/interp.c" target="_blank">https://raw.githubusercontent.com/OpenSmalltalk/opensmalltalk-vm/Cog/spurstacksrc/vm/interp.c</a></span></font> </div><div><br></div><div>One thing I'm curious about is why...   </div><div>searching on "externalNewMethod" shows it is inlined several times, </div><div>but StackInterpreter>>executNewMethod doesn't have the inline pragma   ??</div><div><br></div><div><br></div><div>Now a naive question, since as a 13,000 line function its a bit hard to absorb intepret()...</div><div>why inline by direct code 

generation   rather than as using the "inline" directive on individually generated functions ??</div><div><a href="http://www.drdobbs.com/the-new-c-inline-functions/184401540" target="_blank">http://www.drdobbs.com/the-new-c-inline-functions/184401540</a><br></div><div>(I quite like how that shows the function being folded inline and then function parameters optimized away)</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>So another reason slowPrimitiveResponse is slow is that it writes and reads localFP, localSP & localIP to/from framePointer, stackPointer & instructionPointer.  </div></div></div></blockquote><div><br></div><div><div>Also, along the same naive track, why not inline the primitive C functions so that </div><div>you don't need to manually {externalize,internalize}IPandSP  and make those primitives faster ??</div></div><div>I guess it wouldn't work for instructionsPointer, with definitions like...</div><div><br></div><div><div>    _iss char * stackPointer; //gobal</div><div>    _iss char * framePointer; //global</div><div>    _iss usqInt instructionPointer;  //global</div><div>    sqInt </div><div>    interpret(void)</div><div>    {   char * localFP;</div><div>        char * localIP;</div><div>        char * localSP;</div></div><div><br></div><div><div>   StackInterpreter >> externalizeIPandSP</div><div>        instructionPointer := self oopForPointer: localIP.</div><div>        stackPointer := localSP.</div><div>        framePointer := localFP</div></div><div><br></div><div>Now on page 594 of the Bluebook I read "The fetchByte routine fetches the</div><div>byte indicated by the activecontext's  instruction pointer and increments the instructionPointer"</div><div>That sounds like each Context has its own instructionPointer, but I didn't think that was so ??</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>But because it does so, primitives that change the execution context (process switch primitives that switch to another "stack" of contexts, or eval primitives such as perform:with:* and value:value* which build another frame) can be written and change the execution context at a send point (primitive invocation is always at a send). </div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><br></div><div>Note that all the internal methods have non-internal duals that do the same thing but use framePointer, stackPointer & instructionPointer, not localFP, localSP & localIP.  These are used to implement the eval primitives perform:* and withArgs:executeMethod: since these may also invoke primitives.  And hence you might be able to get your head around my favorite Smalltalk construction:</div><div><div><span style="white-space:pre-wrap">  </span>| array |</div><div><span class="gmail-m_-1937334142108943247gmail-m_5648037065607964588gmail-Apple-tab-span" style="white-space:pre-wrap">  </span>array := { #perform:withArguments:. nil }.</div><div><span class="gmail-m_-1937334142108943247gmail-m_5648037065607964588gmail-Apple-tab-span" style="white-space:pre-wrap"> </span>array at: 2 put: array.</div><div><span class="gmail-m_-1937334142108943247gmail-m_5648037065607964588gmail-Apple-tab-span" style="white-space:pre-wrap">    </span>array perform: array first withArguments: array</div></div><div>;-)</div></div></div></blockquote><div><br></div><div>That's rather recursively evil.</div><div> </div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>Given the primitives are always invoked at a send we can see how elegant Dan's invention of primitive failure is.  Primitives are essentially transactional and atomic.  They validate their arguments and if validation succeeds they carry out their action and answer a result as if from some normal send.  But if validation fails, or if they are unimplemented, the method containing the primitive reference (<primitive: 61>, <primitive: 'primitiveSocketAccept' module: 'SocketPlugin'>) is simply activated as if the primitive didn't exist, or as if the method was a normal method.  Hence primitives are optional, in that if the method body does what the primitive does then no one can tell if the primitive is doing the work or Smalltalk code, except by measuring performance.  Hence for example large integer arithmetic and string display primitives are optional and serve to accelerate the system.<br></div><div><br></div><div>There is one other route by which primitives are executed, also at the point of send, and this is via the special selector bytecocdes.  Another of Dan's excellent optimizations, the special selectors both save space and make the interpreter faster.  They save space by encoding the 32 most frequently occurring sends as one byte bytecodes, hence saving the 2 (16-bit Smalltalk-80), 4 (32-bit Squeak) or 8 (64-bit Squeak) bytes to store the selector in a method's literal frame.  But some of them also speed up the interpreter by statically predicting the receiver type.  i.e. #+, #-, $/ #*, #<, #>, #<= et al are most often sent to integers, and hence these bytecodes, as specified in the Blue Book, check for the top two elements on the stack being SmallIntegers, and if so replace the two top elements by the result of the operation, avoiding a send and primitive dispatch.  Note that in the BttF interpreter this checking is extended both to apply to Float, </div></div></div></blockquote><div><br></div><div>In the BlueBook Bluebook p619 I see the simple bytecode dispatch...</div><div>    currentBytecode = 176 ifTrue: [ ^self primitiveAdd].</div><div>and...</div><div>Bluebook Interpreter >> primitiveAdd </div><div>    | integerReceiver integerArgument integerResult | </div><div>    integerArgument := self poplnteger. </div><div>    integerReceiver := self poplnteger. </div><div>    self success </div><div>        ifTrue: [</div><div><span style="white-space:pre">         </span>    integerResult := integerReceiver + integerArgument. </div><div>            self success: (memory islntegerValue: integerResult)]. </div><div>    self success </div><div>        ifTrue:  [self pushlnteger: integerResult] </div><div>        ifFalse: [self unPop: 2] </div><div><br></div><div><div>and notice that StackInterpreter is doing a lot more within the bytecode before a primitive is needed...</div><div>spurstacksrc/vm/interp.c has... </div><div>     case 176: /* bytecodePrimAdd */</div><div>which is...</div><div>StackInterpreter >> bytecodePrimAdd</div><div><span style="white-space:pre">       </span>| rcvr arg result |</div><div><span style="white-space:pre">   </span>rcvr := self internalStackValue: 1.</div><div><span style="white-space:pre">   </span>arg := self internalStackValue: 0.</div><div><span style="white-space:pre">    </span>(objectMemory areIntegers: rcvr and: arg)</div><div><span style="white-space:pre">             </span>ifTrue: [result := (objectMemory integerValueOf: rcvr) + (objectMemory integerValueOf: arg).</div><div><span style="white-space:pre">                          </span>(objectMemory isIntegerValue: result) ifTrue:</div><div><span style="white-space:pre">                                 </span>[self internalPop: 2 thenPush: (objectMemory integerObjectOf: result).</div><div><span style="white-space:pre">                                        </span>^ self fetchNextBytecode "success"]]</div><div><span style="white-space:pre">                </span>ifFalse: [self initPrimCall.</div><div><span style="white-space:pre">                          </span>self externalizeIPandSP.</div><div><span style="white-space:pre">                              </span>self primitiveFloatAdd: rcvr toArg: arg.</div><div><span style="white-space:pre">                              </span>self internalizeIPandSP.</div><div><span style="white-space:pre">                              </span>self successful ifTrue: [^ self fetchNextBytecode "success"]].</div><div><br></div><div><span style="white-space:pre">     </span>messageSelector := self specialSelector: 0.</div><div><span style="white-space:pre">   </span>argumentCount := 1.</div><div><span style="white-space:pre">   </span>self normalSend</div></div><div><br></div><div><div><span style="white-space:pre">       </span></div><div>Now I'm curious about the different handling above of integers (ifTrue: path) and floats (ifFalse: path).</div><div>I guess the integer code is due to being immediate values where the object doesn't need to be looked up,</div><div>while the non-immediate floats need a primitive call.</div><div>Now I'm wondering, since 64-bit has immediate floats, is bytecodePrimAdd due an update to make them faster?<br></div><div><br></div><div>btw, my impression is that  #areImmediateIntegers:and:  seems a more explicit name that  #areIntegers:and:  </div><div>since I guess the ifTrue: path doesn't apply to integers that are LargePositiveIntegers.</div></div><div><br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>and to check for a fool,lowing branch after the conditionals #<, #<= et al, so that the result doesn't have to be reified into a boolean that is tested immediately; effectively the following branch gets folded into the relational special selector bytecode.  </div></div></div></blockquote><div><br></div><div>Very interesting to know.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>The JIT uses this same technique, but is able to do a much better job because, for example, it can know if a relational special selector send is followed by a jump bytecode or not an JIT time.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><br></div><div><div><br></div></div><div><br></div><div><div>So I understand that checkForEventsMayContextSwitch: called at the end of internalActivateNewMethod<br>occurs after bytecode execution has completed, so that context switches made there are done "between" bytecodes.</div><div>However my perspective is that internalExecuteNewMethod is only half way through a bytecode execution when </div><div>the primitives effect context changes.  So internalActivateNewMethod ends up working on a different Process than internalExecuteNewMethod started with.  The bottom three red lines in the chart are what I considered to be changing threads "half way" through a bytecode.</div></div></div></div></blockquote><div><br></div><div>More accurately, checkForEventsMayContextSwitch: is called on activating a method, after the send has occurred, but before the first bytecode has executed.  Hence primitive sends are not suspension points unless the primitive is a process switch or eval primitive.  Instead, just as a non-primitive (or failing primitive) method is being activated checkForEventsMayContextSwitch: is invoked.</div></div></div></blockquote><div><br></div><div>On BlueBook page 594 I see checkProcessSwitch is called at the start of the cycle rather than the end we have.</div><div>Probably its buried in history, but do you know of any particular reason for the change?</div><div> </div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div>Ahh, I'm slowly coming to grips with this.  It was extremely confusing at the time why my failure code from the primitive was turning up in a different Process, though I then learnt a lot digging to discover why.   In summary, if the primitive succeeds it simply returns from internalExecuteNewMethod and internalActivateNewMethod never sees the new Process B.  My problem violating the primitive-failure side-effect rule was that internalActivateNewMethod trying to run Process A in-Image-primitive-failure code <br></div><div>instead ran Process B in-Image-primitive-failure code.</div></div></div></div></blockquote><div><br></div><div>Right.  So that design requirement is key to the VM architecture.  That was something I had to explain to Alistair when he did the first cut of the FileAttributesPlugin, which used to return failure codes on error instead of failing, leaving error recovery to clients.  And so it underscores the importance of reading the blue book specification.  [We really should do an up-to-date version that describes a simplified 32-bit implementation].</div></div></div></blockquote><div><br></div><div>That would be great.  First step would be to seek permission to reuse that chapter.  </div><div>It would be best to reuse most of its structure and content and update details.</div><div><br></div><div>cheers -ben</div></div></div></div></div></div></div></div></div></div>