Callbacks with Jitter Interpreter

Ian Piumarta piumarta at prof.inria.fr
Wed Feb 4 22:05:36 UTC 1998


Ale,

> I want to port callbacks to the new Jitter Interpreter, but I don't
> know what to do to fetch a bytecode and dispatch it.

The jitter has no interpreter loop.  When it executes a CompiledMethod
it first translates it into TranslatedMethod containing direct-
threaded code, where each "opcode" is represented by the address of
its implementation within the VM.  Execution proceeds by jumping to
the address of the implementation of the next opcode to be executed.

Each opcode's implementation:

    performs its work
    increments the localIP
    reads the next opcode (i.e. address) from "self longAt: localIP"
    jumps to this address

(the last three steps are implemented by the nextOp() macro, defined
in "sqMachDep.h".)

The "dispatch loop" is therefore non-existent: it's spread out over
the implementations of every opcode.

> interpretNextByteCode
> 	currentBytecode _ opcodeIndex.
> 	self dispatchOn: currentBytecode in: OpcodeTable.!

No cigar.  opcodeIndex is only used during initialisation, when the
jitter enumerates it over the opcode encodings and calls the
interpreter "loop" to initialise the opcodeTable.

The loop never even iterates.  The only reason that the interpreter
"loop" looks vaguely like a loop in the source code (if you look
you'll see a "[...] whileTrue: [...]" which is never executed more
than once for each call to #interpret) is to fool dumb compilers into
thinking that there is an arbitrary control flow between the various
"case"s in the dispatch "switch".  Without this "fake loop" these
compilers tend to optimise important stuff away, resulting in a very
broken VM.

(If we had a decent implementation of "#pragma unknown_control_flow"
in every C compiler, there wouldn't be anything remotely resembling a
loop in the jitter's #interpret method.)

> What must I do to run the DynamicInterpreter loop until some
> condition?

Excellent question.  I've no idea what the (efficient) solution might
be.

The only common point in the "dispatch" (i.e. transferring control
from one opcode's implementation to the next opcode's implementation)
is the nextOp() macro.  A single extra instruction in code compiled
from this macro makes a *measurable* difference to the jitter's speed;
introducing a conditional test would kill performance stone dead.

The jitter equivalent of having two interpreter loops, one of which
conditionally returns before executing the next "bytecode", would be
to compile two completely independent versions of each opcode -- one
version using the regular nextOp(), and the other using a version of
nextOp() that conditionally returns.

Sorry that I can't be more helpful.  :(

> (Remember that I am in a callback, similar to be inside a primitive)

Which begs the question: how to you cope with garbage collection
during a callback?

Regards,

Ian
------------------------------- projet SOR -------------------------------
Ian Piumarta, INRIA Rocquencourt,          Internet: Ian.Piumarta at inria.fr
BP105, 78153 Le Chesnay Cedex, FRANCE         Voice: +33 1 39 63 52 87
----------------------- Systemes a Objets Repartis -----------------------





More information about the Squeak-dev mailing list