I. Overview of control transfer instruction


Program flow cannot be separated from conditional control. In order to support conditional jump, the virtual machine provides a large number of bytecode instructions, which can be roughly divided into

  • Comparison instruction,
  • Conditional jump instruction,
  • Compare conditional jump instructions,
  • Multi-conditional branch jump instruction,
  • Unconditional jump instruction, etc.

We also mentioned earlier that there are comparison instructions, which compare the size of two top stack elements and push the result

Comparison instructions are: DCMPG, DCMPL, FCMPG, FCMPL, LCMP

Like the previous instruction, the first character d denotes double, f denotes float, and l denotes long

For double and float numbers, there are two versions of the comparison instruction each because of NaN

Take float as an example, there are two FCMPG and FCMPL instructions. The difference lies in the different results of processing NaN values when comparing numbers

The instructions DCMPL and DCMPG are similar, and their meanings can be inferred from their names, which will not be repeated here

The LCMP instruction is for long integers. Since long integers have no NaN value, there is no need to prepare two sets of instructions

For example, compare the

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

The instructions FCMPG and FCMPL both pop two operands off the stack and compare them

Let the top element of the stack be v2, and the second element in the core top order be v1

If v1=v2, push 0. If v1>v2, push 1. If v1

Two, control transfer instruction of the conditional jump instruction


Conditional jump instructions are usually used in combination with comparison instructions.

Before the conditional jump instruction is executed, the comparison instruction can be used to prepare the top elements of the stack, and then the conditional jump can be performed

The conditional jump instructions are iFEQ, IFLT, IFle, IFNE, IFGT, IFGE, IFNULL, and IFNonNULL

Each of these instructions receives two byte operands that are used to calculate the jump position (16-bit symbol integer as offset to the current position)

Their common meaning is to pop the top of the stack to test whether it satisfies a condition, and if so, jump to a given location

Specific instructions are shown in the figure below:

Note: the same as the previous operation rules

For Boolean, byte, char, short, and conditional branch comparisons, we use the int comparison instruction

For conditional branch comparisons of types long, float, or double, the comparison instruction of the corresponding type is first executed, which returns an integer value to the operand stack, and then the conditional comparison of type int is performed to complete the jump

Because comparison types are eventually converted to ints, the conditional branching instructions for ints are the richest and most powerful.

Let’s use sample code to see what a conditional jump instruction looks like.

public class IfSwitchGotoTest { //1. Public void compare1(){int a = 0; if(a == 0){ a = 10; }else{ a = 20; }}}

Next we compile the code and use the plug-in to see what the specific bytecode looks like.

Let’s take a look at the bytecode instructions and see what they do.







Let’s use the sample code to see what a conditional jump instruction looks like.

public class IfSwitchGotoTest { //1. Public Boolean compareNull(String STR){if(STR == null){return tlue; }else{ return false; }}}

Next we compile the code and use the plug-in to see what the specific bytecode looks like.

Let’s do the next example code to see what different conditional jump instructions look like.

Public class IfSwitchGotoTest {// combine the comparison instruction public void compare2() {float f1 = 9; f1oat f2 = 10; system.out.print1n(f1 < f2); }}

Next we compile the code and use the plug-in to see what the specific bytecode looks like.

Let’s take a look at the bytecode instructions and see what they do.





Three, control transfer instruction comparison condition jump instruction explanation


A comparison conditional jump instruction is similar to a combination of a comparison and conditional jump instruction. It combines the two steps of comparison and jump into one

Such instructions are if_ICmPEq, IF_ICMPne, IF_ICMPDT, IF_ICMPGT, IF_ICmple, IF_ICMPge, if_ACmPEq, and if_ACMPne

The instruction mnemonic is added with “if_”, the instruction beginning with the character “I” is for int integer operation (also includes short and byte type), and the instruction beginning with the character “a” is for object reference comparison.

Each of these instructions takes a two-byte operand as a parameter to calculate the jump position.

At the same time when the instruction is executed, two elements need to be prepared at the top of the stack for comparison. After the instruction is executed, the top two elements are cleared and no data is pushed on the stack. If none of the preconditions is true, the jump is performed. Otherwise, the next statement continues.

Let’s use the sample code to see how conditional jump instructions compare.

public class IfSwitchGotoTest {
    
    public void ifCompare3(){
        Object obj1 = new Object();
        Object obj2 = new Object();
        system.out.println(obj1 == obj2);
        system.out.println(obj1 != obj2);
    }
}

Next we compile the code and use the plug-in to see what the specific bytecode looks like.

Four, control transfer instruction of multi-condition branch jump instruction


The multi-conditional branch jump instruction is designed for switch-case statements. Tableswitch and LookupSwitch are the main types.

In mnemonic terms, both are implementations of the switch statement. The difference between them is:

Tableswitch instruction requires that the branch values of multiple conditions are continuous. It stores only the start value and end value and several jump offsets. With the given operand index, the jump offsets can be located immediately, so the efficiency is relatively high

Each discrete case-offset pair is stored in the lookupSwitch instruction. Every time it is executed, all the case-offset pairs should be searched to find the matching case value and calculate the jump address according to the corresponding offset, so the efficiency is low

Next, for a basic test of the multi-conditional branch jump instruction, look at the sample code below

Public void swtich1(int select){int num; switch(select){ case 1: num = 10; break; case 2: num = 20; break; case3: num = 30; break; default: num = 40; }}

Let’s compile the code and see what happens to the bytecode of the swtich1 method.

What happens if the case in our switch branch does not end with a break? Take a look at the sample code

public void swtich1(int select){ int num; switch(select){ case 1: num = 10; break; case 2: num = 20; case3: num = 30; break; default: num = 40; }}

Let’s compile the code and see what happens to the bytecode of the swtich1 method.

Let’s use the next example code to experience the multiple conditional branch jump instruction

public void swtich2(int select){ int num; switch(select){ case 100: num = 10; break; case 500: num = 20; break; case 208: num = 30; break; default: num = 40; }}

Let’s compile the code and see what happens to the bytecode of the swtich2 method.

We know that the new feature in JDK7 is String, so let’s see what the String switch looks like

//jdk7 new feature; Public void swtich3(string season){switch(season){case "SPRING" : break; case "SUMMER" : break; case "AUTUMN" : break; case "WINTER" : break; }}

Let’s compile the code and see what happens to the bytecode of the swtich2 method.

Five, control transfer instruction unconditional jump instruction explanation


At present, the main unconditional jump instruction is goto

The instruction goto receives two bytes of operands, which together form a signed integer that specifies the instruction’s offset. The purpose of execution is to jump to the position at which the offset is given

If the instruction offset is too large, beyond the range of a double-byte signed integer, the instruction goto_w can be used. It has the same function as goto, but it receives 4-byte operands and can represent a much larger address range

Although JSR, JSR_w, and RET are also unconditional jump, they are mainly used in try-finally statements and have been gradually abandoned by virtual machines, so these two instructions are not introduced here