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?
-
Example please. Hard to tell what you're talking about otherwise. Impossible, really. – user207421 Mar 14 '17 at 07:38
-
Elaborate your question please. – Pratik Ambani Mar 14 '17 at 07:48
-
You cannot possibly answer that question satisfactorily in a comment. Edit it into your question, where it should have been in the first place. – user207421 Mar 14 '17 at 08:13
-
Sorry for my fault. Here is an example from [The Java Virtual Mechine Specification (Java SE 8 Edition)](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html#jvms-3.2). You can look at the "dspin" function in this section. Thanks.@EJP @Pratik Ambani – Q_SJ Mar 14 '17 at 08:14
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.

- 37,781
- 10
- 100
- 107
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.
-
If I delete all the `store` and `load`, then can the code above still work? – Q_SJ Mar 14 '17 at 10:36
-
If I understand you correctly, you mean in some situation the javac really generate an aubudent pair of `store` and `load`. Am I right? – Q_SJ Mar 14 '17 at 12:10
-
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.

- 298
- 3
- 14