Thread

gilles81 Messages postés 72 Statut Membre -  
BlueMind Messages postés 583 Statut Membre -
Bonjour,
après avoir lu tout ceci , je ne comprends toujours pas ce que c'est qu'un "direct code thread".Quelqu'un peut il m'aider?Et" indirect code thread"
merci

DIRECT THREADED CODE ----------------------------------------------------------------------

Now we'll get to the really crucial bit in understanding FORTH, so go and get a cup of tea
or coffee and settle down. It's fair to say that if you don't understand this section, then you
won't "get" how FORTH works, and that would be a failure on my part for not explaining it well.
So if after reading this section a few times you don't understand it, please email me
(rich@annexia.org).

Let's talk first about what "threaded code" means. Imagine a peculiar version of C where
you are only allowed to call functions without arguments. (Don't worry for now that such a
language would be completely useless!) So in our peculiar C, code would look like this:

f ()
{
a ();
b ();
c ();
}

and so on. How would a function, say 'f' above, be compiled by a standard C compiler?
Probably into assembly code like this. On the right hand side I've written the actual
i386 machine code.

f:
CALL a E8 08 00 00 00
CALL b E8 1C 00 00 00
CALL c E8 2C 00 00 00
; ignore the return from the function for now

"E8" is the x86 machine code to "CALL" a function. In the first 20 years of computing
memory was hideously expensive and we might have worried about the wasted space being used
by the repeated "E8" bytes. We can save 20% in code size (and therefore, in expensive memory)
by compressing this into just:

08 00 00 00 Just the function addresses, without
1C 00 00 00 the CALL prefix.
2C 00 00 00

On a 16-bit machine like the ones which originally ran FORTH the savings are even greater - 33%.

[Historical note: If the execution model that FORTH uses looks strange from the following
paragraphs, then it was motivated entirely by the need to save memory on early computers.
This code compression isn't so important now when our machines have more memory in their L1
caches than those early computers had in total, but the execution model still has some
useful properties].

Of course this code won't run directly on the CPU any more. Instead we need to write an
interpreter which takes each set of bytes and calls it.

On an i386 machine it turns out that we can write this interpreter rather easily, in just
two assembly instructions which turn into just 3 bytes of machine code. Let's store the
pointer to the next word to execute in the %esi register:

08 00 00 00 <- We're executing this one now. %esi is the _next_ one to execute.
%esi -> 1C 00 00 00
2C 00 00 00

The all-important i386 instruction is called LODSL (or in Intel manuals, LODSW). It does
two things. Firstly it reads the memory at %esi into the accumulator (%eax). Secondly it
increments %esi by 4 bytes. So after LODSL, the situation now looks like this:

08 00 00 00 <- We're still executing this one
1C 00 00 00 <- %eax now contains this address (0x0000001C)
%esi -> 2C 00 00 00

Now we just need to jump to the address in %eax. This is again just a single x86 instruction
written JMP *(%eax). And after doing the jump, the situation looks like:

08 00 00 00
1C 00 00 00 <- Now we're executing this subroutine.
%esi -> 2C 00 00 00

To make this work, each subroutine is followed by the two instructions 'LODSL; JMP *(%eax)'
which literally make the jump to the next subroutine.

And that brings us to our first piece of actual code! Well, it's a macro.
*/

/* NEXT macro. */
.macro NEXT
lodsl
jmp *(%eax)
.endm

/* The macro is called NEXT. That's a FORTH-ism. It expands to those two instructions.

Every FORTH primitive that we write has to be ended by NEXT. Think of it kind of like
a return.

The above describes what is known as direct threaded code.

To sum up: We compress our function calls down to a list of addresses and use a somewhat
magical macro to act as a "jump to next function in the list". We also use one register (%esi)
to act as a kind of instruction pointer, pointing to the next function in the list.

I'll just give you a hint of what is to come by saying that a FORTH definition such as:

: QUADRUPLE DOUBLE DOUBLE ;

actually compiles (almost, not precisely but we'll see why in a moment) to a list of
function addresses for DOUBLE, DOUBLE and a special function called EXIT to finish off.

At this point, REALLY EAGLE-EYED ASSEMBLY EXPERTS are saying "JONES, YOU'VE MADE A MISTAKE!".

I lied about JMP *(%eax).
A voir également:

1 réponse

BlueMind Messages postés 583 Statut Membre 159
 
Salut,

C'est simple, tout est dis ...

So if after reading this section a few times you don't understand it, please email me
(rich@annexia.org).


:-)

Sinon ben pareil pour moi.
0