<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body 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>
    Best, Lars<br>
    <br>
    <div class="moz-cite-prefix">2013/01/28 10:28 pm Eliot Miranda
      <a class="moz-txt-link-rfc2396E" href="mailto:eliot.miranda@gmail.com">&lt;eliot.miranda@gmail.com&gt;</a>:<br>
    </div>
    <blockquote
cite="mid:CAC20JE3QEUYPs58XHgG+Ei_EfXGp_JtU=htf0R3BO7S8W32eOg@mail.gmail.com"
      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 moz-do-not-send="true"
            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'm still sometimes working on cog ARM, but due to my
          studies I have little time. The problem I'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'm not happy with that location for this behavior,
          but I don'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>
          &nbsp; &nbsp; 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>
          &nbsp; &nbsp; 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. &nbsp;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's point of view. &nbsp;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 (*). &nbsp;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's the prolog for a normal method,
          expressed in the VM's assembler:</div>
        <div><br>
        </div>
        <div>
          <div>LstackOverflow:</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>MoveCq:
            0 R: ReceiverResultReg</div>
          <div>LsendMiss:</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>Call:
            ceMethodAbortTrampoline</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>AlignmentNops:
            (BytesPerWord max: 8)</div>
          <div>Lentry:</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>objectRepresentation
            getInlineCacheClassTagFrom: ReceiverResultReg into: TempReg</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>CmpR:
            ClassReg R: TempReg</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>JumpNonZero:
            LsendMiss:</div>
          <div>LnoCheckEntry:</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>...
            frame bulding code ...</div>
          <div>
            <span class="Apple-tab-span" style="white-space:pre"> </span>MoveAw:
            coInterpreter stackLimitAddress R: TempReg</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>CmpR:
            TempReg R: SPReg</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </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. &nbsp;The link register defnitely
          needs to be pushed for the send miss. &nbsp;It doesn'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 class="Apple-tab-span" style="white-space:pre"> </span>MoveCq:
            0 R: ReceiverResultReg</div>
          <div>LsendMiss:</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>Push:
            LinkReg</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>Call:
            ceMethodAbortTrampoline</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>AlignmentNops:
            (BytesPerWord max: 8)</div>
        </div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>...</div>
        <div><br>
        </div>
        <div>and in&nbsp;ceMethodAbortTrampoline there would be a test
          on&nbsp;ReceiverResultReg so that if&nbsp;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&nbsp;ceMethodAbortTrampoline call, and
          if&nbsp;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&nbsp;ceMethodAbortTrampoline call and the outer return address
          is that for the send call that missed. &nbsp;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. &nbsp;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 class="Apple-tab-span" style="white-space:pre"> </span>"<i>The
              start of a CogMethod has a call to a run-time abort
              routine that either</i></div>
          <div><i><span class="Apple-tab-span" style="white-space:pre">
              </span> handles an in-line cache failure or a stack
              overflow. &nbsp;The routine selects the</i></div>
          <div><i><span class="Apple-tab-span" style="white-space:pre">
              </span> path depending on ReceiverResultReg; if zero it
              takes the stack overflow</i></div>
          <div><i><span class="Apple-tab-span" style="white-space:pre">
              </span> path; if nonzero the in-line cache miss path.
              &nbsp;Neither of these paths returns.</i></div>
          <div><i><span class="Apple-tab-span" style="white-space:pre">
              </span> The abort routine must be called; &nbsp;In the callee
              the method is located by</i></div>
          <div><i><span class="Apple-tab-span" style="white-space:pre">
              </span> adding the relevant offset to the return address
              of the call.</i>"</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>stackOverflowCall
            := self MoveCq: 0 R: ReceiverResultReg.</div>
          <span class="Apple-tab-span" style="white-space:pre"> </span>backEnd
          hasLinkRegister ifTrue:</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span><span
            class="Apple-tab-span" style="white-space:pre"> </span>[self
          PushR: LinkReg].</div>
        <div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>sendMissCall
            := self Call: (self methodAbortTrampolineFor:
            methodOrBlockNumArgs)</div>
        </div>
        <div><br>
        </div>
        <div>StackToRegisterMappingCogit methods for initialization</div>
        <div>
          <div>genMethodAbortTrampolineFor: numArgs&nbsp;</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span></div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>"Generate
            the abort for a method. &nbsp;This abort performs either a call
            of ceSICMiss:</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>
            to handle a single-in-line cache miss or a call of
            ceStackOverflow: to handle a</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>
            stack overflow. &nbsp;It distinguishes the two by testing
            ResultReceiverReg. &nbsp;If the</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>
            register is zero then this is a stack-overflow because a)
            the receiver has already</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>
            been pushed and so can be set to zero before calling the
            abort, and b) the</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>
            receiver must always contain an object (and hence be
            non-zero) on SIC miss."</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>|
            jumpSICMiss |</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>&lt;var:
            #jumpSICMiss type: #'AbstractInstruction *'&gt;</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>opcodeIndex
            := 0.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>self
            CmpCq: 0 R: ReceiverResultReg.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>jumpSICMiss
            := self JumpNonZero: 0.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>backEnd
            hasLinkRegister ifTrue:</div>
          <div><span class="Apple-style-span"><span
                class="Apple-tab-span" style="white-space:pre"> </span><span
                class="Apple-tab-span" style="white-space:pre"> </span>[self
              MoveR: LinkReg Mw: 0 r: SPReg]. "overwrite send ret
              address with&nbsp;</span>ceMethodAbortTrampoline<span
              class="Apple-style-span">&nbsp;call ret address"</span></div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>self
            compileTrampolineFor: #ceStackOverflow:</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>callJumpBar:
            true</div>
          <div>
            <span class="Apple-tab-span" style="white-space:pre"> </span>numArgs:
            1</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>arg:
            SendNumArgsReg</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>arg:
            nil</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>arg:
            nil</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>arg:
            nil</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>saveRegs:
            false</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>resultReg:
            nil.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>jumpSICMiss
            jmpTarget: self Label.</div>
        </div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>backEnd
          hasLinkRegister ifTrue:</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span><span
            class="Apple-tab-span" style="white-space:pre"> </span>[self
          PushR: LinkReg]. "push ret address for&nbsp;ceMethodAbortTrampoline
          call"</div>
        <div>
        </div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>...</div>
        <div><br>
        </div>
        <div><br>
        </div>
        <div>The same goes for the aborts in closed and open PICs. &nbsp;Does
          this make sense?</div>
        <div>(*) I'm not sure without looking at the code carefully
          whether any frameless methods can make calls on the runtime.
          &nbsp;If not, then this issue is moot. &nbsp;If so, then one solution is
          to not compile the method frameless if it makes use of the
          run-time. &nbsp;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>
  </body>
</html>