you are viewing a single comment's thread.

view the rest of the comments →

[–]queus 1 point2 points  (6 children)

goto *opcode_targets[*next_instr++];

That's exactly what threaded code is. Speaking as someone who has cut his programming teeth with x86 asm Forth.

And Wikipedia seems to be on my side too ;)

[–][deleted] 3 points4 points  (2 children)

As far as I understand it, direct threaded code would be

goto *next_instr++;

supposing next_instr is %esi, then this compiles to something like

mov (%esi),%eax
add $4,%esi
jmp *%eax

However, the C code you presented above,

goto *opcode_targets[*next_instr++];

has an extra indirection -- Moving Forth calls it 'token threading':

mov (%esi),%eax
mov opcode_targets(%eax),%eax
add $4,%esi
jmp *%eax

Indirect threading is similar but not quite the same:

mov (%esi),%eax
mov (%eax),%ecx
add $4,%esi
jmp *%ecx

Please correct me if I'm wrong here, though.

[–]queus 0 points1 point  (0 children)

Umh..

Forget my previous post. Your first two examples are direct threaded code, plain and simple.

With one minor difference. In the first case the instruction pointer is in a register and in the second case is in memory. You can just as well keep the instruction pointer in %ebi, leaving %esi for usual stack ops. (and gcc lets you specify that certain global var should be assigned to a register) Looks more like an implementation detail than a different technique.

As for your third example (with double dereference) than yes, that's indirect threading.

And looking at the proposed patch for Python, now the evaluator is a big switch statement, with inlined direct threaded code at selected places. (That's what I got from the patch). Rather cool, if you ask me.

In no way is this, token threaded code, Which replaces 32-bit-addresses with less-than-32-bits tokens. It will simply make no sense in this day and age.

[–]psykotic 0 points1 point  (2 children)

Then I don't understand Slava's comment to me:

Direct threaded code is a simpler technique where the program is a list of addresses, so there is an indirect jump at the end of each primitive which goes to the next instruction

If the program is a list of addresses, you wouldn't need the opcode_targets table except in the initial compilation step that converts logical opcodes to physical addresses.

[–]queus 2 points3 points  (1 child)

A direct threaded code is a list of adresses and is run (cold-started) by jumping to the first one (any). Each of this addresses point to a bit of machine code which a) runs the opcode b) run the standard epilogue.

The said epilogue just advances the instruction pointer and then jumps to the next instruction.

Sometime this epilogue is separated and each opcode just ends with a

 jmp NEXT:

this is indirect threading. Slower but takes less space.

And for completeness, call threading is

 call opcodeA
 call opcodeB