Author: Whiteknight
Date: Fri Dec 12 18:14:08 2008
New Revision: 33844
Modified:
trunk/docs/book/ch12_opcodes.pod
Log:
[Book] Add more information about the CGP core, and some small fixes about the
CG core.
Modified: trunk/docs/book/ch12_opcodes.pod
==============================================================================
--- trunk/docs/book/ch12_opcodes.pod (original)
+++ trunk/docs/book/ch12_opcodes.pod Fri Dec 12 18:14:08 2008
@@ -127,7 +127,7 @@
C<void **> values. In the computed goto core, all the labels represent
different opcodes, so they are stored in an array:
- void **my_labels[] = {
+ void *my_labels[] = {
&&label1,
&&label2,
&&label3
@@ -142,29 +142,60 @@
Jumping to one of these labels is done with a command like this:
- goto my_labels[opcode_number];
+ goto *my_labels[opcode_number];
Actually, opcodes are pointed to by an C<opcode_t *> pointer, and all
opcodes are stored sequentially in memory, so the actual jump in the
computed goto core must increment the pointer and then jump to the new
version. In C it looks something like this:
- goto my_labels[*(current_opcode += 1)];
+ goto *my_labels[*(current_opcode += 1)];
-Each opcode is a label, and at the end of each opcode an instruction like
-this is performed to move to the next opcode in series, or else some
-kind of control flow occurs that moves it to a non-sequential location:
+Each opcode is an index into the array of labels, and at the end of each
+opcode an instruction like this is performed to move to the next opcode
+in series, or else some kind of control flow occurs that moves it to a
+non-sequential location:
- goto my_lables[*(current_opcode = destination)];
+ goto *my_lables[*(current_opcode = destination)];
These are simplifications on what really happens in this core, because
the actual code has been optimized quite a bit from what has been
-presented here.
+presented here. However, as we shall see with the precomputed goto core,
+it isn't optimized as aggressively as is possible.
=item* Precomputed Goto Core
-Thought the Computed Goto core was hard enough to understand? Precomputed
-goto takes the concept a little further.
+The precomputed goto core is an amazingly optimized fast core that uses
+the same computed goto feature, but performs the array dereferencing
+before the core even starts. In the computed goto core, you have this
+operation to move to the next opcode:
+
+ goto *my_labels[*(current_opcode += 1)];
+
+This single line of code is deceptively complex. A number of machine code
+operations must be performed to complete this step: The value of
+C<current_opcode> must be incremented to the next value, that value must
+be dereferenced to find the opcode value. In C, arrays are pointers, so
+C<my_labels> gets dereferenced and an offset is taken according to find
+the stored label reference. That label reference is then dereferenced, and
+the jump is performed.
+
+That's a lot of steps to execute before we can jump to the next opcode.
+Now, what, if each opcode value was replaced with the value of the jump
+label beforehand? If C<current_opcode> points to a label referenced
+already, we don't need the array at all. We can replace that entire mess
+above with this line:
+
+ goto **(current_opcode += 1);
+
+That's far fewer machine instructions to execute before we can move to the
+next opcode, which means faster throughput. Remember that whatever dispatch
+mechanism is used will be called after every singly opcode, and some large
+programs may have millions of opcodes! Every single machine instruction
+that can be cut out of the dispatch mechanism could increase the execution
+speed of Parrot in a significant and noticable way. The precomputed goto
+core, while not available on all compilers, takes the idea of optimization
+to the extreme.
=item* Tracing Core