Interpreter>>pushReceiverVariableBytecode

Ian Piumarta ian.piumarta at inria.fr
Sat Sep 7 00:02:03 UTC 2002


Stephen,

On Fri, 6 Sep 2002, Stephen Pair wrote:

> Ok, I see how the CCodeGenerator is making this method work...but I
> still don't see why it's necessary to do the #fetchNextBytecode first

A traditional interpreter loop looks like this:

  while (1) {
    int bytecode= fetchNextBytecode();
    switch (bytecode)
    { ... 256 cases ...; break; }
  }

and introduces a potential execution stall (in the processor) between the
fetching of the bytecode and the dispatch to the corresponding case label
(the processor might have to wait several cycles for the bytecode to
arrive from memory before being able to proceed to use it).

The thing to notice is that the above is semantically equivalent to this:

  int bytecode= fetchNextBytecode();
  while (1) {
    switch (bytecode)
    {
      case N: doTheWork();
              bytecode= fetchNextBytecode();
              break;
      ... x 256 ...
    }
  }

from where it's trivial to see that

    switch (bytecode)
    {
       case N: bytecode= fetchNextBytecode();
               doTheWork();
               break;
    }

is the same too (modulo your problem which isn't a problem in interp.c
because the var becomes a constant during CCodeGen) -- except that now we
might have avoided the stall (because even if it takes several cycles to
fetch the bytecode from memory, this can happen in parallel with
doingTheWork).

> (which isn't correct if you're running in Smalltalk).

This method is overridden in InterpSimulator precisely for that reason.

> Why can't the #fetchNextBytecode be the last statement as it is in the
> InterpreterSimulator version of this method?

Because the speedup is measurable, _significantly_ so when using gcc in
which case the final "break" in each bytecode is converted (manually, by
an awk script run on the interp.c file) into an explicit dispatch directly
to the next bytecode's case label

   void *bytecodeDisatchTable[256] = { &label0, ..., &label255 };
   ...
   case N: labelN:
           bytecode= fetchNextBytecode();
           doTheWork();
           goto *bytecodeDispatchTable[currentBytecode]; /* break */

which entirely eliminates the interpreter's dispatch loop.

I hope this helps to explain why things are the way they are.

Regards,

Ian




More information about the Squeak-dev mailing list