<div class="gmail_quote"><div class="gmail_quote"><div class="im">On Tue, Jan 29, 2013 at 1:59 PM, Lars <span dir="ltr">&lt;<a href="mailto:lars.wassermann@googlemail.com" target="_blank">lars.wassermann@googlemail.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

  
    
  
  <div text="#000000" bgcolor="#FFFFFF">
    Of those four calling conventions, I was only aware of the first and
    the third. The explanation about the difference between (3) and (4)
    clarifies your remarks about the changes to the compileAbort method.<br>
    <br>
    But the point of the initial mail stands as a question:<br>
        If the interpreter does only understand platform C calling
    convention (1) (and virtual St-St(4)), don&#39;t we have to change the
    simulator to be able to use it with the ARM-Trampolines?<br></div></blockquote><div><br></div></div><div>No I don&#39;t think so.  The trick is in Cogit&gt;&gt;handleCallOrJumpSimulationTrap: and each processor alien&#39;s simulateCallOf:nextpc:memory: method.  In the simulator, when a trampoline executes a call instruction that calls an interpreter routine it calls an illegal address and that causes a ProcessorSimulationTrap exception which is caught by Cogit&gt;&gt;simulateCogCodeAt:, which defers to handleSimulationTrap:, which defers via handleCallOrJumpSimulationTrap: to simulateCallOf:nextpc:memory:.  In the case of BochsIA32Alien this pushes the next pc (pushes the return address), builds a stub frame and sets the instruction pointer to the illegal address, i.e. it simulates the call of the interpreter routine.  In GdbARMAlien it isn&#39;t implemented yet.  It simply sets the link register and the pc.  But it should really construct a frame that looks like a simple C frame, so it should read something like:</div>

<div><br></div><div><div>simulateCallOf: address nextpc: nextpc memory: aMemory</div><div><span style="white-space:pre-wrap">        </span>&quot;Simulate a frame-building call of address.  Build a frame since</div>
<div><span style="white-space:pre-wrap">        </span>a) this is used for calls into the run-time which are unlikely to be leaf-calls, and</div><div><span style="white-space:pre-wrap">        </span>b) stack alignment needs to be realistic for assert checking for platforms such as Mac OS X.</div>

<div><span style="white-space:pre-wrap">        </span>N.B. r11 is typically the platform&#39;s frame pointer, if it uses one.&quot;</div><div><span style="white-space:pre-wrap">        </span>self pushWord: nextpc in: aMemory.</div>
<div><span style="white-space:pre-wrap">        </span>self pushWord: self r11 in: aMemory.</div><div><span style="white-space:pre-wrap">        </span>self r11: self sp.</div><div><span style="white-space:pre-wrap">        </span>self pc: address</div>

</div><div><br></div><div><br></div><div>I don&#39;t know the details (e.g. whether frames do save a frame pointer, and whether r112 is used for the frame pointer).  Copy the platform&#39;s C compiler.</div><div><br></div>

<div>Now simulateCallOf:nextpc:memory: pairs with simulateReturnIn:.</div><div><br></div><div>Further, simulateLeafCallOf:nextpc:memory: pairs with simulateLeafReturnIn: and these are easy; you&#39;ve already implemented the first:</div>

<div><br></div><div><div>simulateLeafCallOf: address nextpc: nextpc memory: aMemory</div><div><span style="white-space:pre-wrap">        </span>self lr: nextpc.</div><div><span style="white-space:pre-wrap">        </span>self pc: address</div>

</div><div><br></div><div>and that should pair with:</div><div><div>simulateLeafReturnIn: aMemory</div><div><span style="white-space:pre-wrap">        </span>self pc: self lr</div></div><div><br></div><div>Can I cc this to vm-dev?</div>
<div><div class="h5">
<div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div text="#000000" bgcolor="#FFFFFF">
    <div>2013/01/29 9:48 pm Eliot Miranda
      <a href="mailto:eliot.miranda@gmail.com" target="_blank">&lt;eliot.miranda@gmail.com&gt;</a>:<br>
    </div><div><div>
    <blockquote type="cite"><br>
      <br>
      <div class="gmail_quote">On Tue, Jan 29, 2013 at 1:01 AM, Lars <span dir="ltr">&lt;<a href="mailto:lars.wassermann@googlemail.com" target="_blank">lars.wassermann@googlemail.com</a>&gt;</span>
        wrote:<br>
        <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
          <div text="#000000" bgcolor="#FFFFFF"> Hi Eliot,<br>
            it seems I am not solving the right problem. As far as I
            understood, we have to support ARM abi, because the (gcc
            compiled) interpreter is expected to be called that way.
            What we do within the (JIT compiled) machine code is up to
            us.<br>
            <br>
            But how I understood your email is the opposite: The
            translated interpreter will always adhere to IA32 abi, and
            only within machine code, we want to push the LinkReg, etc.<br>
            How is that possible? Are there flags when compiling the
            c-code for ARM to use IA32 abi instead?<br>
            <br>
            Or is my mental model still off?<br>
          </div>
        </blockquote>
        <div><br>
        </div>
        <div>yes, but only a little :).  there are four calling
          conventions to think about, one virtual.  In no particular
          order they are:</div>
        <div><br>
        </div>
        <div>One is the platform&#39;s C calling convention.  This is
          defined by the platform and not something we can decide.  It
          must be used whenever we cal a function in the interpreter, be
          it a run-time routine or a primitive.  Most of the run-time
          routines are called through trampolines and these trampolines
          must convert their input arguments into a valid call on the
          relevant interpreter routine according to the platform ABI.</div>
        <div><br>
        </div>
        <div>Two is the trampoline calling convention(s).  This is
          purely register-based, and is used for generated machine-code
          to call the interpreter.  These are defined by the call
          instruction used to invoke them.  On X86 the return address
          will be passed on the stack.  On ARM it will be passed in the
          linkRegister (I think) and pushed there-in (in those
          trampolines that need to return back).</div>
        <div><br>
        </div>
        <div>Three is the Smalltalk-to-Smalltalk calling convention used
          in sends, here, like two, n X86 the return address will be
          passed on the stack.  On ARM it will be passed in the
          linkRegister and pushed in frame-building code.  This
          convention is register-based for 0 and 1 argument sends, and
          both register-and-stack-based for &gt; 1 argument sends (with
          the receiver and the class/selector always passed in a
          register).</div>
        <div><br>
        </div>
        <div>Four is the virtual form of three, which is observed by the
          interpreter at various send failure points.  In this calling
          convention the return address is always passed on the stack,
          and is used by the interpreter to find the method or PIC in
          which a send has failed, and beneath that is the return
          address of the failing send call, which the interpreter uses
          to locate the send site that may be modified to maintain the
          inline cache.</div>
        <div><br>
        </div>
        <div>So calling convention one is defined by the platform and we
          must adhere to it.</div>
        <div><br>
        </div>
        <div>Calling convention two is a simple fast limited calling
          convention for a limited set of calls into the interpreter
          that insulates the generated machine code from the platform&#39;s
          calling conventions.</div>
        <div> </div>
        <div>Calling convention three is a simple fast calling
          convention used for machine-code Smalltalk-to-Smalltalk calls.</div>
        <div><br>
        </div>
        <div>Calling convention four is a virtualization of calling
          convention three that insulated the interpreter from the
          processor&#39;s implementation of call and return instructions.</div>
        <div><br>
        </div>
        <div>Does this resolve things?</div>
        <div><br>
        </div>
        <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
          <div text="#000000" bgcolor="#FFFFFF"> Best, Lars<br>
          </div>
        </blockquote>
        <div><br>
        </div>
        <div>cheers!</div>
        <div> </div>
        <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
          <div text="#000000" bgcolor="#FFFFFF"> <br>
            <div>2013/01/28 10:28 pm Eliot Miranda <a href="mailto:eliot.miranda@gmail.com" target="_blank">&lt;eliot.miranda@gmail.com&gt;</a>:<br>
            </div>
            <div>
              <div>
                <blockquote type="cite">Hi Lars,<br>
                  <br>
                  <div class="gmail_quote">On Sat, Jan 26, 2013 at 1:16
                    PM, Lars <span dir="ltr">&lt;<a href="mailto:lars.wassermann@googlemail.com" target="_blank">lars.wassermann@googlemail.com</a>&gt;</span>
                    wrote:<br>
                    <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
                      Hello Eliot, hello vm-dev,<br>
                      <br>
                      @vm-dev: I&#39;m still sometimes working on cog ARM,
                      but due to my studies I have little time. The
                      problem I&#39;m working on is that IA32 has a
                      different function call ABI than ARM. While on
                      IA32, you need to push the return address, on ARM,
                      you load it into the LR-register.<br>
                      <br>
                      A design decision to accommodate this difference
                      in the ARM JIT was to use IA32 ABI within all cog
                      code, even when running on ARM. Only when calling
                      the (compiled) interpreter, we use ARM ABI. The
                      hope was, that this way we need to change little
                      of the existing code.<br>
                      <br>
                      @all: In the last days of working (spread across
                      several months), I implemented the Call opcode
                      (which is used by cogit whenever a function is
                      called) by pushing the return address before
                      branching to the target (IA32 ABI).<br>
                      Also, I changed the trampoline generation to ask
                      the compiler for the appropriate call opcode for
                      the ABI (so far not committed), which is either
                      Call in case of IA32 or BL in case of ARM. I&#39;m not
                      happy with that location for this behavior, but I
                      don&#39;t know whether there exists a better place.
                      Also, #hasLinkRegister is implemented on the
                      compiler.<br>
                      <br>
                      Now, that calling the interpreter has changed, I
                      run into the problem, that the simulator is
                      expecting the stack pointer to point to the return
                      address. The simulator is assuming IA32 ABI.<br>
                      <br>
                      How best to attribute for the changed ABI in the
                      simulator?<br>
                          Subclass the simulator? On which level,
                      VMSimulator or VMSimulatorLSB? That change would
                      be orthogonal to the LSB subclass (if there ever
                      will be a MSB subclass).<br>
                          Or introduce two classes which do know the ABI
                      and are responsible for all places where ABI is
                      used? Also the eventual changes to trampoline and
                      enilopmart generation? Which problems might arise
                      from this design decision with respect to the
                      C-translation?<br>
                    </blockquote>
                    <div><br>
                    </div>
                    <div><br>
                    </div>
                    <div>I would take the same approach that Peter
                      Deutsch took in HPS, the VisualWorks VM.  The idea
                      is to keep the Interpreter side of things
                      unchanged and change the glue code and/or the
                      generated method prologue code to keep the stack
                      the same from the Interpreter&#39;s point of view.  So
                      when an ARM machine code method calls another ARM
                      machine code method the link register is in use,
                      and the frame building code in a frame-building
                      non-leaf method pushes the link register as part
                      of building the frame (as one would expect), and a
                      frameless method may be able to return through the
                      link register if it contains no runtime calls, but
                      wold have to if it does (*).  But if a
                      machine-code method calls the run-time through
                      glue it would push the link register at some point
                      before the glue call, leaving the stack in the
                      same state as it would be in the IA32 version at
                      the same point in execution.</div>
                    <div><br>
                    </div>
                    <div>For example, here&#39;s the prolog for a normal
                      method, expressed in the VM&#39;s assembler:</div>
                    <div><br>
                    </div>
                    <div>
                      <div>LstackOverflow:</div>
                      <div><span style="white-space:pre-wrap"> </span>MoveCq:

                        0 R: ReceiverResultReg</div>
                      <div>LsendMiss:</div>
                      <div><span style="white-space:pre-wrap"> </span>Call:

                        ceMethodAbortTrampoline</div>
                      <div><span style="white-space:pre-wrap"> </span>AlignmentNops:

                        (BytesPerWord max: 8)</div>
                      <div>Lentry:</div>
                      <div><span style="white-space:pre-wrap"> </span>objectRepresentation

                        getInlineCacheClassTagFrom: ReceiverResultReg
                        into: TempReg</div>
                      <div><span style="white-space:pre-wrap"> </span>CmpR:

                        ClassReg R: TempReg</div>
                      <div><span style="white-space:pre-wrap"> </span>JumpNonZero:

                        LsendMiss:</div>
                      <div>LnoCheckEntry:</div>
                      <div><span style="white-space:pre-wrap"> </span>...

                        frame bulding code ...</div>
                      <div> <span style="white-space:pre-wrap"> </span>MoveAw:

                        coInterpreter stackLimitAddress R: TempReg</div>
                      <div><span style="white-space:pre-wrap"> </span>CmpR:

                        TempReg R: SPReg</div>
                      <div><span style="white-space:pre-wrap"> </span>JumpBelow:

                        LstackOverflow</div>
                    </div>
                    <div><br>
                    </div>
                    <div>The ceMethodAbort handles both the send miss
                      when the inline cache fails, and stack overflow at
                      the end of a stack page or to check for events.
                       The link register defnitely needs to be pushed
                      for the send miss.  It doesn&#39;t need to be pushed
                      for the stack overflow (since frame build code has
                      already saved it in the return pc slot in the
                      frame), but pushing it unnecessarily can be undone
                      by the glue for ceMethodAbortTrampoline.</div>
                    <div><br>
                    </div>
                    <div>So the abort code would become</div>
                    <div><br>
                    </div>
                    <div>
                      <div>LstackOverflow:</div>
                      <div><span style="white-space:pre-wrap"> </span>MoveCq:

                        0 R: ReceiverResultReg</div>
                      <div>LsendMiss:</div>
                      <div><span style="white-space:pre-wrap"> </span>Push:

                        LinkReg</div>
                      <div><span style="white-space:pre-wrap"> </span>Call:

                        ceMethodAbortTrampoline</div>
                      <div><span style="white-space:pre-wrap"> </span>AlignmentNops:

                        (BytesPerWord max: 8)</div>
                    </div>
                    <div><span style="white-space:pre-wrap"> </span>...</div>
                    <div><br>
                    </div>
                    <div>and in ceMethodAbortTrampoline there would be a
                      test on ReceiverResultReg so that
                      if ReceiverResultReg is 0 (the stack overflow
                      case) the link register is written to the same
                      stack slot as it was pushed to, so that the top of
                      stack is the return address for
                      the ceMethodAbortTrampoline call, and
                      if ReceiverResultReg is non-zero (the send miss
                      case), the link register is pushed, so that the
                      inner return address on top of stack is the return
                      address for the ceMethodAbortTrampoline call and
                      the outer return address is that for the send call
                      that missed.  The return addresses are used to
                      identify the method (whose selector is the
                      selector of the send) and the calsite at which the
                      send missed.</div>
                    <div><br>
                    </div>
                    <div>So with a little modification in the right
                      places the Interpreter sees exactly the same stack
                      with ARM machine code as it does on IA32.  In fact
                      we can construct tests to ensure this is the case
                      by running two VMs side by side, running some test
                      image that exercises the send machinery etc.</div>
                    <div><br>
                    </div>
                    <div>As far as the code codes it might look
                      something like:</div>
                    <div><br>
                    </div>
                    <div><i>Cogit methods for compile abstract
                        instructions</i></div>
                    <div>
                      <div><b>compileAbort</b></div>
                      <div><span style="white-space:pre-wrap"> </span>&quot;<i>The

                          start of a CogMethod has a call to a run-time
                          abort routine that either</i></div>
                      <div><i><span style="white-space:pre-wrap"> </span>
                          handles an in-line cache failure or a stack
                          overflow.  The routine selects the</i></div>
                      <div><i><span style="white-space:pre-wrap"> </span>
                          path depending on ReceiverResultReg; if zero
                          it takes the stack overflow</i></div>
                      <div><i><span style="white-space:pre-wrap"> </span>
                          path; if nonzero the in-line cache miss path.
                           Neither of these paths returns.</i></div>
                      <div><i><span style="white-space:pre-wrap"> </span>
                          The abort routine must be called;  In the
                          callee the method is located by</i></div>
                      <div><i><span style="white-space:pre-wrap"> </span>
                          adding the relevant offset to the return
                          address of the call.</i>&quot;</div>
                      <div><span style="white-space:pre-wrap"> </span>stackOverflowCall

                        := self MoveCq: 0 R: ReceiverResultReg.</div>
                      <span style="white-space:pre-wrap"> </span>backEnd

                      hasLinkRegister ifTrue:</div>
                    <div><span style="white-space:pre-wrap"> </span><span style="white-space:pre-wrap"> </span>[self
                      PushR: LinkReg].</div>
                    <div>
                      <div><span style="white-space:pre-wrap"> </span>sendMissCall

                        := self Call: (self methodAbortTrampolineFor:
                        methodOrBlockNumArgs)</div>
                    </div>
                    <div><br>
                    </div>
                    <div>StackToRegisterMappingCogit methods for
                      initialization</div>
                    <div>
                      <div>genMethodAbortTrampolineFor: numArgs </div>
                      <div><span style="white-space:pre-wrap"> </span></div>
                      <div><span style="white-space:pre-wrap"> </span>&quot;Generate

                        the abort for a method.  This abort performs
                        either a call of ceSICMiss:</div>
                      <div><span style="white-space:pre-wrap"> </span>
                        to handle a single-in-line cache miss or a call
                        of ceStackOverflow: to handle a</div>
                      <div><span style="white-space:pre-wrap"> </span>
                        stack overflow.  It distinguishes the two by
                        testing ResultReceiverReg.  If the</div>
                      <div><span style="white-space:pre-wrap"> </span>
                        register is zero then this is a stack-overflow
                        because a) the receiver has already</div>
                      <div><span style="white-space:pre-wrap"> </span>
                        been pushed and so can be set to zero before
                        calling the abort, and b) the</div>
                      <div><span style="white-space:pre-wrap"> </span>
                        receiver must always contain an object (and
                        hence be non-zero) on SIC miss.&quot;</div>
                      <div><span style="white-space:pre-wrap"> </span>|
                        jumpSICMiss |</div>
                      <div><span style="white-space:pre-wrap"> </span>&lt;var:

                        #jumpSICMiss type: #&#39;AbstractInstruction *&#39;&gt;</div>
                      <div><span style="white-space:pre-wrap"> </span>opcodeIndex

                        := 0.</div>
                      <div><span style="white-space:pre-wrap"> </span>self

                        CmpCq: 0 R: ReceiverResultReg.</div>
                      <div><span style="white-space:pre-wrap"> </span>jumpSICMiss

                        := self JumpNonZero: 0.</div>
                      <div><span style="white-space:pre-wrap"> </span>backEnd

                        hasLinkRegister ifTrue:</div>
                      <div><span><span style="white-space:pre-wrap"> </span><span style="white-space:pre-wrap"> </span>[self
                          MoveR: LinkReg Mw: 0 r: SPReg]. &quot;overwrite
                          send ret address with </span>ceMethodAbortTrampoline<span> call
                          ret address&quot;</span></div>
                      <div><span style="white-space:pre-wrap"> </span>self

                        compileTrampolineFor: #ceStackOverflow:</div>
                      <div><span style="white-space:pre-wrap"> </span>callJumpBar:

                        true</div>
                      <div> <span style="white-space:pre-wrap"> </span>numArgs:

                        1</div>
                      <div><span style="white-space:pre-wrap"> </span>arg:

                        SendNumArgsReg</div>
                      <div><span style="white-space:pre-wrap"> </span>arg:

                        nil</div>
                      <div><span style="white-space:pre-wrap"> </span>arg:

                        nil</div>
                      <div><span style="white-space:pre-wrap"> </span>arg:

                        nil</div>
                      <div><span style="white-space:pre-wrap"> </span>saveRegs:

                        false</div>
                      <div><span style="white-space:pre-wrap"> </span>resultReg:

                        nil.</div>
                      <div><span style="white-space:pre-wrap"> </span>jumpSICMiss

                        jmpTarget: self Label.</div>
                    </div>
                    <div><span style="white-space:pre-wrap"> </span>backEnd

                      hasLinkRegister ifTrue:</div>
                    <div><span style="white-space:pre-wrap"> </span><span style="white-space:pre-wrap"> </span>[self
                      PushR: LinkReg]. &quot;push ret address
                      for ceMethodAbortTrampoline call&quot;</div>
                    <div> </div>
                    <div><span style="white-space:pre-wrap"> </span>...</div>
                    <div><br>
                    </div>
                    <div><br>
                    </div>
                    <div>The same goes for the aborts in closed and open
                      PICs.  Does this make sense?</div>
                    <div>(*) I&#39;m not sure without looking at the code
                      carefully whether any frameless methods can make
                      calls on the runtime.  If not, then this issue is
                      moot.  If so, then one solution is to not compile
                      the method frameless if it makes use of the
                      run-time.  Another approach would be to build a
                      simple frame (just push the link register).</div>
                    <div><br>
                    </div>
                    <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
                      <br>
                      All the best,<br>
                      Lars<br>
                      <br>
                      <br>
                    </blockquote>
                  </div>
                  <br>
                  <br clear="all">
                  <div><br>
                  </div>
                  -- <br>
                  best,
                  <div>Eliot</div>
                </blockquote>
                <br>
              </div>
            </div>
          </div>
        </blockquote>
      </div>
      <br>
      <br clear="all">
      <div><br>
      </div>
      -- <br>
      best,
      <div>Eliot</div>
    </blockquote>
    <br>
  </div></div></div>

</blockquote></div></div></div><span class="HOEnZb"><font color="#888888"><br><br clear="all"><div><br></div>-- <br>best,<div>Eliot</div>
</font></span></div><br><br clear="all"><div><br></div>-- <br>best,<div>Eliot</div>