<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    Hi Eliot,<br>
    thank you for the analysis.<br>
    The question is why the code works with the VM, but not if we step
    through it. What does the VM do that makes this behave correctly,
    although the temps-array is removed from the stack prior to
    returning from #contextOn:do:?<br>
    <br>
    I ask because I need to recreate that behaviour in case it also
    appears in other places. The general&nbsp; project is creating a squeak
    research VM. That is also why I try to refrain from changing the
    image, retaining compatibility with Pharo/Squeak trunk.<br>
    <br>
    Thank you, Lars<br>
    <br>
    <div class="moz-cite-prefix">2013/05/17 8:08 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:CAC20JE10hUy1C89-wL6=2T6O0L=aT-QW1od4BanS-dKcVQ3b0w@mail.gmail.com"
      type="cite">
      <pre wrap=""> </pre>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <br>
      Hi Lars,<br>
      <br>
      <div class="gmail_quote">On Fri, May 17, 2013 at 9:36 AM, Lars
        Wassermann <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">&nbsp;<br>
          Hello VM-dev,<br>
          I habe problems understanding what exactly happens when I step
          through:<br>
          (ContextPart contextOn: Error do: []) halt<br>
          in a workspace.<br>
          When I step over the parenthesis in the debugger, everything
          works kind of like expected (the context of contextOn:do:
          misses one temporary but the returned value is what the
          methods description promised). When I step into or through the
          code, an error is raised when executing bytecode 54 of
          #contextOn:do:, because the temps-array illegally has been
          poped (by bytecode 53).<br>
          <br>
          My question now is:<br>
          Why does the normal vm not only break when runing this code,
          but also return the correct value (the first element of the
          last temporary).<br>
          I appended a graphic trying to visualize what happens up to
          the miracle of three skipped bytecodes.<br>
        </blockquote>
        <div><br>
        </div>
        <div>Ugh. &nbsp;I hate this method. &nbsp; Actually I hate
          ContextPart&gt;&gt;jump, which is the really evil method.</div>
        <div><br>
        </div>
        <div>So let's take a look at the methods:</div>
        <div><br>
        </div>
        <div>ContextPasrt class&gt;&gt;contextOn: exceptionClass do:
          block</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>"Create
          an #on:do: context that is ready to return from executing its
          receiver"</div>
        <div><br>
        </div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>|
          ctxt chain |</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>ctxt
          := thisContext.</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>[chain
          := thisContext sender cut: ctxt. ctxt jump]</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span><span
            class="Apple-tab-span" style="white-space:pre"> </span>on:
          exceptionClass</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span><span
            class="Apple-tab-span" style="white-space:pre"> </span>do:
          block.</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>"jump
          above will resume here without unwinding chain"</div>
        <div><span class="Apple-tab-span" style="white-space:pre"> </span>^
          chain</div>
        <div><br>
        </div>
        <div>answers a context that is an activation of on:do: ready to
          catch the supplied exception. &nbsp;It is used by
          ContextPart&gt;&gt;runUntilErrorOrReturnFrom: to insert an
          exception handler for UnhandledError immediately beneath the
          current context being executed by the debugger.</div>
        <div><br>
        </div>
        <div>The on:do: argument is a little unclear. &nbsp;It is easier to
          understand if it reads</div>
        <div><br>
        </div>
        <div>
          <div>ContextPasrt class&gt;&gt;contextOn: exceptionClass do:
            block</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>"Create
            an #on:do: context that is ready to return from executing
            its receiver"</div>
          <div><br>
          </div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>|
            ctxt onDoContext |</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>ctxt
            := thisContext.</div>
          <div><span class="Apple-style-span"><span
                class="Apple-tab-span" style="white-space:pre"> </span>[</span>onDoContext<span
              class="Apple-style-span">&nbsp;:= thisContext sender.</span></div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>&nbsp;onDoContext&nbsp;cut:
            ctxt.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>&nbsp;ctxt
            jump]</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span><span
              class="Apple-tab-span" style="white-space:pre"> </span>on:
            exceptionClass</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span><span
              class="Apple-tab-span" style="white-space:pre"> </span>do:
            block.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>"jump
            above will resume here without unwinding chain"</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>^&nbsp;onDoContext</div>
        </div>
        <div><br>
        </div>
        <div>So the idea is to run until in the on:do:'s receiver (the
          [onDoContext := ...] block), grab the sender (the on:do:
          activation), remove intervening contexts (onDoContext cut:
          ctxt) so that on:do:'s handlerActive doesn't get set, resume
          executing in the contextOn:do: context (ctxt jump) and answer
          the onDoContext.</div>
        <div><br>
        </div>
        <div>The horror is in ContextPart&gt;&gt;jump:</div>
        <div><br>
        </div>
        <div>
          <div>ContextPart&gt;&gt;jump</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>"Abandon
            thisContext and resume self instead (using the same current
            process). &nbsp;You may want to save thisContext's sender before
            calling this so you can jump back to it.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>Self
            MUST BE a top context (ie. a suspended context or a
            abandoned context that was jumped out of). &nbsp;A top context
            already has its return value on its stack (see
            Interpreter&gt;&gt;primitiveSuspend and other suspending
            primitives).</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>thisContext's
            sender is converted to a top context (by pushing a nil
            return value on its stack) so it can be jump back to."</div>
          <div><br>
          </div>
          <div>
            <span class="Apple-tab-span" style="white-space:pre"> </span>|
            top |</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>"Make
            abandoned context a top context (has return value (nil)) so
            it can be jumped back to"</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>thisContext
            sender push: nil.</div>
          <div><br>
          </div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>"Pop
            self return value then return it to self (since we jump to
            self by returning to it)"</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>stackp
            = 0 ifTrue: [self stepToSendOrReturn].</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>stackp
            = 0 ifTrue: [self push: nil]. &nbsp;"must be quick return
            self/constant"</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>top
            := self pop.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>thisContext
            privSender: self.</div>
          <div><span class="Apple-tab-span" style="white-space:pre"> </span>^
            top</div>
        </div>
        <div><br>
        </div>
        <div>This works by returning to self (a MethodContext), but
          return pushes a result. &nbsp;So the code pops the top thing off
          the stack and returns it. &nbsp;This is evil. &nbsp;If the stack is
          empty then this will pop the receiver, return it and push it
          back in the return (!!). &nbsp;If the stack contains only temps
          then the last temp is popped and pushed by the return (!!).
          &nbsp;This is what you're seeing. &nbsp;The stack's last temp is an
          indirection vector. &nbsp;It gets popped off the stack by</div>
        <span class="Apple-tab-span" style="white-space:pre"> </span>top
        := self pop.</div>
      <div class="gmail_quote">at which point any attempt to look at
        self's temps in a debugger will cause an error because the
        indirection vector is no longer there. &nbsp;It then gets pushed back
        by=</div>
      <div class="gmail_quote"><span class="Apple-tab-span"
          style="white-space:pre"> </span>^ top</div>
      <div class="gmail_quote"><br>
      </div>
      <div class="gmail_quote">Horrible. &nbsp;It all depends on being able
        to create a temporary invalid execution state in a context.</div>
      <div class="gmail_quote"><br>
      </div>
      <div class="gmail_quote">A better way to do this is by process
        switch, avoiding the return. &nbsp;For example, in my basic block
        profiler I handle an unknownBytecode error caused by executing
        the unknownBytecode that overwrites the bytecode at the
        beginning of each basic block, replaces the unknownBytecode with
        the correct bytecode, and continues:</div>
      <div class="gmail_quote"><br>
      </div>
      <div class="gmail_quote">
        <div class="gmail_quote">ContextPart&gt;&gt;unusedBytecode</div>
        <div class="gmail_quote">
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>"Handle unusedBytecode by
            replacing the bytecode with the</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>&nbsp;correct one found in the
            coverage property and continuing.</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>&nbsp;Continue via wait/signal
            since return would push a result."</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>| coverage semaphore
            process |</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>self assert: (method at:
            pc) = method encoderClass unusedBytecode.</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>coverage := method
            propertyValueAt: #coverage.</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>self assert: coverage
            notNil.</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>self assert: (coverage
            includesKey: pc).</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>semaphore := Semaphore
            new.</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>process := Processor
            activeProcess.</div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>[method</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>at: pc</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>put: (coverage removeKey:
            pc).</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>&nbsp;process suspendedContext
            unwindTo: self.</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>&nbsp;process
            suspendedContext: self.</div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>&nbsp;semaphore signal] fork.</div>
          <div class="gmail_quote"><br>
          </div>
          <div class="gmail_quote"><span class="Apple-tab-span"
              style="white-space:pre"> </span>semaphore wait</div>
        </div>
        <div class="gmail_quote"><br>
        </div>
        <div class="gmail_quote">So that could become something like</div>
        <div class="gmail_quote"><br>
        </div>
        <div class="gmail_quote">
          <div class="gmail_quote">jump</div>
          <div class="gmail_quote">
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>"Abandon thisContext
              and resume self instead (using the same current process).
              &nbsp;You may want to save thisContext's sender before calling
              this so you can jump back to it.</div>
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>Self MUST BE a top
              context (ie. a suspended context or a abandoned context
              that was jumped out of). &nbsp;A top context already has its
              return value on its stack (see
              Interpreter&gt;&gt;primitiveSuspend and other suspending
              primitives)."</div>
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>| semaphore process |</div>
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>semaphore := Semaphore
              new.</div>
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>process := Processor
              activeProcess.</div>
            <div class="gmail_quote"><br>
            </div>
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>[process
              suspendedContext unwindTo: self.</div>
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>&nbsp;process
              suspendedContext: self.</div>
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>&nbsp;semaphore signal]
              fork.</div>
            <div class="gmail_quote"><br>
            </div>
            <div class="gmail_quote"><span class="Apple-tab-span"
                style="white-space:pre"> </span>semaphore wait</div>
            <div><br>
            </div>
            <div>but perhaps the process switch will introduce other
              problems. &nbsp;I don't know.</div>
            <div><br>
            </div>
            <div>Hope this helps.</div>
            <div><br>
            </div>
          </div>
        </div>
        <blockquote class="gmail_quote" style="margin:0 0 0
          .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
          I replicated the behavior in Squeak 4.0 and 4.4 images on
          interpreter VMs 3.7.7, 4.10, and a newer cog VM.<br>
          <br>
          <br>
          A fix to the problem of stepping and comprehension as well as
          the missing temp in the frame would be changing the method to:<br>
          <br>
          contextOn: exceptionClass do: block<br>
          &nbsp; &nbsp; &nbsp; &nbsp; "Create an #on:do: context that is ready to return
          from executing its receiver"<br>
          <br>
          &nbsp; &nbsp; &nbsp; &nbsp; | ctxt chain |<br>
          &nbsp; &nbsp; &nbsp; &nbsp; ctxt := thisContext.<br>
          &nbsp; &nbsp; &nbsp; &nbsp; [chain := thisContext sender cut: ctxt.<br>
          &nbsp; &nbsp; &nbsp; &nbsp; ctxt push: nil. ctxt jump] on: exceptionClass do:
          block.<br>
          &nbsp; &nbsp; &nbsp; &nbsp; "jump above will resume here without unwinding chain"<br>
          &nbsp; &nbsp; &nbsp; &nbsp; ^ chain<br>
          <br>
          The difference is that after cutting off ctxt, we ensure that
          it is a top context by pushing a meaningless value. But this
          still doesn't help me understanding the original behaviour.<br>
          <br>
          Thank you and all the best<br>
          Lars<br>
          <br>
        </blockquote>
      </div>
      <br>
      <br clear="all">
      <div><br>
      </div>
      -- <br>
      best,
      <div>Eliot</div>
    </blockquote>
    <br>
  </body>
</html>