In computer programming, a branch table or jump table is a method of transferring program control (branching) to another part of a program (or a different program that may have been dynamically loaded) using a table of branch or jump instructions. It is a form of multiway branch. The branch table construction is commonly used when programming in assembly language but may also be generated by compilers, especially when implementing optimized switch statements whose values are densely packed together.[1]
A branch table consists of a serial list of unconditional branch instructions that is branched into using an offset created by multiplying a sequential index by the instruction length (the number of bytes in memory occupied by each branch instruction). It relies on the fact that machine code instructions for branching have a fixed length and can be executed extremely efficiently by most hardware, and is most useful when dealing with raw data values that may be easily converted to sequential index values. Given such data, a branch table can be extremely efficient. It usually consists of the following 3 steps:
The following pseudocode illustrates the concept
Another method of implementing a branch table is with an array of pointers from which the required function's address is retrieved. Originally known as transfer vector, this method is also more recently known under such different names as "dispatch table" or "virtual method table" but essentially performing exactly the same purpose. This pointer function method can result in saving one machine instruction, and avoids the indirect jump (to one of the branch instructions).
The resulting list of pointers to functions is almost identical to direct threaded code, and is conceptually similar to a control table.
The actual method used to implement a branch table is usually based on:
Use of branch tables and other raw data encoding was common in the early days of computing when memory was expensive, CPUs were slower and compact data representation and efficient choice of alternatives were important. Nowadays, they are commonly still used in:
Advantages of branch tables include:
If
statements)For library functions, where they may be referenced by an integer:
In addition, calling functions by number (the index into the table) can sometimes be useful in some cases in normal application programming.
A simple example of branch table use in the 8-bit Microchip PIC assembly language is:
table ; The branch table begins here with this label goto index_zero ; each of these goto instructions is an unconditional branch goto index_one ; of code. goto index_two goto index_three
index_zero ; Code is added here to perform whatever action is required when INDEX = zero return
index_one ...
Note: this code will work only if PCL < (table + index_last). To ensure this condition we may use an "org" directive. And if GOTO (PIC18F for example) is 2 bytes, this limits the number of table entries to less than 128.
Another simple example, this time demonstrating a jump table rather than a mere branch table. This allows program blocks outside of the currently active procedure/function to be called:
typedef void (*Handler)(void); /* A pointer to a handler function */
/* The functions */void func3 (void) void func2 (void) void func1 (void) void func0 (void)
Handler jump_table[4] = ;
int main (int argc, char **argv)
PL/I implements a jump table as an array of label variables. These may be initialized in an unusual way by using a subscripted statement label. PL/I label variables are not simply the address of the statement, but usually contain additional information on the state of the code block to which they belong. Without the unusual initialization, this could also be coded with calls and an array of entry variables.
declare lab (10) label; declare x fixed binary; goto lab(x); lab(1): /* code for choice 1 */ ; ... lab(2): /* code for choice 2 */ ; ...
Programmers frequently leave the decision of whether or not to create a branch table to the compiler, believing that it is perfectly capable of making the correct choice from the known search keys. This may be true for optimizing compilers for relatively simple cases where the range of search keys is limited. However, compilers are not as intelligent as humans and cannot have a deep knowledge of 'context', believing that a range of possible search key integer values such as 1, 2, 4, 6, 7, 20, 23, 40, 42, 50 & 1000 would generate a branch table with an excessively large number of empty entries (900+) for very little advantage. A good optimizing compiler may then presort the values and generate code for a binary chop search, as a 'second best' option. In fact, the application may be highly "time critical" and memory requirement may not really be an issue at all.[2]
However, a little 'common sense' can transform this particular case, and many other similar cases, to a simple two-step process with very large potential savings, while still eventually leaving the ultimate choice to the compiler, but 'assisting its decision' considerably:
Variations along similar lines can be used in cases where there are two sets of short ranges with a large gap between ranges.
While the technique is now known as 'branch tables', early compiler users called the implementation 'computed GoTo', referring to the instruction found in the Fortran series of compilers.[3] [4] The instruction was eventually deprecated in Fortran 90 (in favour of SELECT & CASE statements at the source level).[5]
Where there is no obvious integer value available for a branch table it can nevertheless be created from a search key (or part of a search key) by some form of arithmetic transformation, or could simply be the row number of a database or the entry number in an array containing the search key found during earlier validation of the key.
A hash table may be required to form the index in some cases. However, for single byte input values such as A-Z (or the first byte of a longer key), the contents of the byte itself (raw data) can be used in a two-step, "trivial hash function", process to obtain a final index for a branch table with zero gaps.
The array would be no larger than (256 × 2) bytes to hold 16-bit unsigned (short) integers for all possible 8-bit bytes.If no validation is required, and only upper case is used, the size of the array may be as small as (26 × 2) = 52 bytes.
Although the technique of branching using a branch table is most frequently used solely for the purpose of altering program flow – to jump to a program label that is an unconditional branch – the same technique can be used for other purposes.For example, it can be used to select a starting point in a sequence of repeated instructions where drop through is the norm and intentional. This can be used for example by optimizing compilers or JIT compilers in loop unrolling.