jvm - Java bytecode: local variables table vs on-stack calculation -


assume have following class:

final class impl implements gateway3 {     private final sensor sensor1;     private final sensor sensor2;     private final sensor sensor3;      private final alarm alarm;      public impl(sensor sensor1, sensor sensor2, sensor sensor3, alarm alarm) {         this.sensor1 = sensor1;         this.sensor2 = sensor2;         this.sensor3 = sensor3;         this.alarm = alarm;     }      @override     public temperature averagetemp() {         final temperature temp1 = sensor1.temperature();         final temperature temp2 = sensor2.temperature();         final temperature temp3 = sensor3.temperature();          final average tempavg = new average.impl(temp1, temp2, temp3);         final temperature result = tempavg.result();         return result;     }      @override     public void poll() {         final temperature avgtemp = this.averagetemp();         this.alarm.trigger(avgtemp);     } 

this class uses local variables , of them final.

if @ bytecode generated for, let's say, averagetemp method, we'll see following bytecode:

   0: aload_0    1: getfield      #2                  // field sensor1:lru/mera/avral/script/bytecode/demo/sensor;    4: invokeinterface #6,  1            // interfacemethod ru/mera/avral/script/bytecode/demo/sensor.temperature:()lru/mera/avral/script/bytecode/demo/temperature;    9: astore_1   10: aload_0   11: getfield      #3                  // field sensor2:lru/mera/avral/script/bytecode/demo/sensor;   14: invokeinterface #6,  1            // interfacemethod ru/mera/avral/script/bytecode/demo/sensor.temperature:()lru/mera/avral/script/bytecode/demo/temperature;   19: astore_2   20: aload_0   21: getfield      #4                  // field sensor3:lru/mera/avral/script/bytecode/demo/sensor;   24: invokeinterface #6,  1            // interfacemethod ru/mera/avral/script/bytecode/demo/sensor.temperature:()lru/mera/avral/script/bytecode/demo/temperature;   29: astore_3   30: new           #7                  // class ru/mera/avral/script/bytecode/demo/average$impl   33: dup   34: aload_1   35: aload_2   36: aload_3   37: invokespecial #8                  // method ru/mera/avral/script/bytecode/demo/average$impl."<init>":(lru/mera/avral/script/bytecode/demo/temperature;lru/mera/avral/script/bytecode/demo/temperature;lru/mera/avral/script/bytecode/demo/temperature;)v   40: astore        4   42: aload         4   44: invokeinterface #9,  1            // interfacemethod ru/mera/avral/script/bytecode/demo/average.result:()lru/mera/avral/script/bytecode/demo/temperature;   49: astore        5   51: aload         5   53: areturn 

there plenty of astore opcodes.

now, assume using bytecode generation library, generated following bytecode same method:

   0: new           #18                 // class ru/mera/avral/script/bytecode/demo/average$impl    3: dup    4: aload_0    5: getfield      #20                 // field sensor1:lru/mera/avral/script/bytecode/demo/sensor;    8: invokeinterface #25,  1           // interfacemethod ru/mera/avral/script/bytecode/demo/sensor.temperature:()lru/mera/avral/script/bytecode/demo/temperature;   13: aload_0   14: getfield      #27                 // field sensor2:lru/mera/avral/script/bytecode/demo/sensor;   17: invokeinterface #25,  1           // interfacemethod ru/mera/avral/script/bytecode/demo/sensor.temperature:()lru/mera/avral/script/bytecode/demo/temperature;   22: aload_0   23: getfield      #29                 // field sensor3:lru/mera/avral/script/bytecode/demo/sensor;   26: invokeinterface #25,  1           // interfacemethod ru/mera/avral/script/bytecode/demo/sensor.temperature:()lru/mera/avral/script/bytecode/demo/temperature;   31: invokespecial #33                 // method ru/mera/avral/script/bytecode/demo/average$impl."<init>":(lru/mera/avral/script/bytecode/demo/temperature;lru/mera/avral/script/bytecode/demo/temperature;lru/mera/avral/script/bytecode/demo/temperature;)v   34: invokevirtual #36                 // method ru/mera/avral/script/bytecode/demo/average$impl.result:()lru/mera/avral/script/bytecode/demo/temperature;   37: areturn 

semantically, new method implementation has same meaning comparing old 1 - still takes temperature value 3 sensors, make average them , returns it. instead of putting intermediate values variables, calculations on stack. can rewrite way since local variables , fields final.

now there question: if doing bytecode-generation-related magic , follow "all calculations on stack" approach everywhere (assuming variables , fields final), potential pitfalls may face?

note: have no intention rewrite bytecode existing java classes in way described. example class given here show method semantics want achieve in bytecode.

as shown andreas’ answer, it’s not unusual have java code utilizing stack temporary values, in nested expressions. that’s why instruction set created way, using operand stack refer calculated value implicitly. in fact, i’d call code example excessive use of local variables unusual.

if input of byte code producing tool not java code, amount of variables might differ typical java code, if of declarative nature, there no requirement have of them directly mapped local variables in byte code.

jvms hotspot transfer code ssa form, transfer operations between local variables , operand stack, pure stack manipulations dup , swap, eliminated anyway, before applying subsequent optimizations, choice of using local variables or not not have performance impact.

it might worth noting can’t inspect values on operand stack in debuggers, might consider retaining variables when making debug build (when localvariabletable generated, too).

some code constructs require local variables. e.g. when have exception handler, entry point have operand stack cleared, containing reference exception, values wants access have materialized local variables. don’t know if input form has loop constructs, if so, convert them declarative form conventional loop using mutable variable under hood, when necessary. mind iinc instruction, works directly local variable…


Comments