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
Post a Comment