Next: Function Returns
Up: Other Conditional Statements
Previous: For
The JVM has two instructions to handle case statements, the
tableswitch and the lookupswitch instruction. The tableswitch
instruction is used when the case values can be efficiently used as
indices into the table of target offsets. When the values are more sparse, it
is better to use the lookupswitch instruction. This instruction looks up
the value of the case in its table of case values and jumps to the offset
where the code of that value is. If the value is not in the table, it takes a
default offset.
Because the lookupswitch instruction will always work, I will use that.
The operands of the instruction contain an offset for every case label of the
case statement. How the list of operands is exactly structured can be
found in [JVM]; a short description of the instruction is given in
subsection 4.2.7. I will only give an idea on how to compute and
fill in the correct offsets when they are known.
The bytecode for a case statement may be structured the following way:
- First the code to load the selector on the operand stack;
- After that the lookupswitch instruction with the table in its
parameterlist;
- After the lookupswitch instruction there is a piece of code for
every case label. Every piece of code, except the last one, is ended with a
goto statement to jump to the first instruction of the code following
the case statement.
As you do not know in advance at what offset the code for a specific case label
begins, you can not fill them in in the table. What you can do is allocate the
entries in the table, i.e. allocate the params structures in the
parameterlist of the instruct structure containing the lookupswitch
instruction, and leave the entries for
the offsets empty. This way you do know the indexes of the instructions
following the lookupswitch instruction, so you can fill the offsets in
when they are known.
To use the labeling algorithm used with the other conditional statements, we
have to change the jmp_label field. Instead of containing an int
value, it must now contain a list of int values. When an instruction is
added to the list, it is now inserted before the first instruct structure
of which the jmp_label field has a value other than the null
pointer, instead of a value other than -1.
A case statement may now be compiled as follows:
- Add the code to load the value of the selector of the case
statement on the operand stack;
- Add the lookupswitch instruction, leaving all the entries for the
offsets empty;
- Save the index of the lookupswitch instruction, so you know where
to find it when you want to fill in the offsets;
- Add an empty instruct structure to the list, which will serve as
the label for the goto instructions of all the pieces of code for the
case labels. The index of the lookupswitch instruction can be added as
entry in the label list;
- For each of the case labels do the following:
- Compute the offset for the case label by subtracting the index of
the lookupswitch from the index of the next instruction to add,
because that is the first instruction of the code for the case label.
Fill in the resulting offset at the appropriate entry in the table in
the parameterlist of the lookupswitch instruction;
- Add the code for the case label, which is inserted before the
label of the goto instructions;
- Add the goto instruction with an empty parameterlist to
jump to the first instruction of the code following the case
statement when the code of this case label has been executed (no
goto for the last case label). This goto instruction is also
inserted before the label of the goto instructions;
- Add the index of the goto instruction to the label list of
the first labeled instruct structure in the list, which is the
structure containing the label list for the goto instructions;
- Resolve the labels of the goto instructions by going through the
label list and for every entry subtract the index from the current index of the
instruct structure containing the label list. The resulting index is
constructed into a parameterlist which is added to the goto instruction
at the index contained in the entry in the label list. When the index of the
lookupswitch instruction is encountered in the label list, compute the
offset the same way as usual and insert it into the table in the parameterlist
of the lookupswitch instruction for the default case label. After all
offsets are computed, remove the instruct structure from the list.
Next: Function Returns
Up: Other Conditional Statements
Previous: For
mark@bottom.xs4all.nl