Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does java bytecode "store" often followed by "load"?

When I read jvm bytecode which from some small java function, I found that when a new local variable is caculated on the operand stack, assuming that it will be stored in the local variable table, but usually it will be loaded to the operand stack immediately (just in the terms of bytecode literally). I don't understand the operation well, is it unnecessary operation?

like image 974
Q_SJ Avatar asked Mar 14 '17 07:03

Q_SJ


3 Answers

The Java compiler tends to compile things in a very simple and straightforward manner, leaving optimization to the JIT.

For example, if you write x *= 3; x *= 4;, you'll probably get bytecode along the lines of

iload_1
iconst_3
imul
istore_1
iload_1
iconst_4
imul
istore_1

The compiler could theoretically figure out that the store/load pair is redundant and remove it. But there are several reasons to not do so - 1) this adds a lot of complexity for no benefit as the JIT optimizes everything anyway 2) it makes debugging harder, since you no longer have access to the values of all the local variables 3) if an exception is somehow thrown in the middle of this expression, the local variables will have the incorrect values.

like image 174
Antimony Avatar answered Nov 04 '22 15:11

Antimony


Looking at the dspin bytecode

Method void dspin()
0   dconst_0       // Push double constant 0.0
1   dstore_1       // Store into local variables 1 and 2
2   goto 9         // First time through don't increment
5   dload_1        // Push local variables 1 and 2 
6   dconst_1       // Push double constant 1.0 
7   dadd           // Add; there is no dinc instruction
8   dstore_1       // Store result in local variables 1 and 2
9   dload_1        // Push local variables 1 and 2 
10  ldc2_w #4      // Push double constant 100.0 
13  dcmpg          // There is no if_dcmplt instruction
14  iflt 5         // Compare and loop if less than (i < 100.0)
17  return         // Return void when done

The only load that follows store is at offset 9. You can see that offset 9 can be reached by two different paths: (1) from offset 2 with goto 9; and (2) sequentially from offset 8

dload_1 pushes the value of local variables 1 and 2 onto the operand stack (two variables because of double): in case (1) when trying to enter the loop for the first time, and in case (2) when trying to enter the loop at later points of time.

Interestingly, in this example if you delete all store and load the behavior of the program will not change. However, the Java compiler usually does not try to be smart. It compiles Java code more or less directly. In this case the local variable i directly corresponds to local variables 1 and 2.

See Optimization by Java Compiler for more information.

like image 41
dejvuth Avatar answered Nov 04 '22 15:11

dejvuth


See, every operation in JVM is done on operand stack. So whenever you have to perform any operation on a variable, you have to first load (pushed ) on the operand stack by load command and then perform operation.

This is why store is followed by load instruction in bytecode.

like image 38
Ratnesh Avatar answered Nov 04 '22 15:11

Ratnesh