This document describes the production patterns for byte code by the jdk 1.4.2 compiler.
cond(A) block AAn if-else statement is compiled as follows:
cond(A) block goto(B) A block B
aload // Load object reference. dup // Duplicate object reference. getfield // Fetch field oldValue. delta // Can be any value, could even be an expression. add/sub // Increment/decrement value. // Stack: ref newValue dup_x1 // Duplicate top and put it on third position. // Stack: newValue ref newValue. putfield // Store field value. // Stack: newValueReduction: ++field, --field, or (field = field + delta), if delta not equal to constant +/-1.
aload // Load object reference. dup // Duplicate object reference. getfield // Fetch field value. // Stack: ref oldValue dup_x1 // Duplicate top and put it on third position. // Stack: oldValue ref oldValue const // Must be constant +/-1. add/sub // Increment/decrement value. // Stack: oldValue ref newValue putfield // Store field value. // Stack: oldValue.Reduction: field++ or field--.
iinc(delta) // Increment variable. load // Load variable. // Stack: newValue
load // Load variable. delta // Any expression. add // Increment. dup // Stack: newValue newValue store // Store to variable. // Stack: newValue
load // Load variable. iinc(delta) // Increment variable. // Stack: oldValue
Note that we could match the pattern [load, iinc, load]
with either (E) [i++, i]
or (C) [i, ++i]
.
Of these obviously equivalent alternatives we choose (E).
While statement: goto(B) A block B cond(A)
Do statement: A block cond(A)
For statement (equivalent to a do statement): init A block increment cond(A)
In Java, a try statement has the following structure:
try Block Catch* (Catch | Finally)
TryCatchFinally: tryBlock Handler // 0..n times DefaultHandler B Finally A jsr(B)
TryCatchFinally: tryBlock goreth Handler goreth // 0..n Handler A
DefaultHandler: (Any Exception) astore_exception jsr(B) aload_exception athrow
Handler: astore_exception catchBlock
Finally: astore_address finallyBlock ret
The store operations in the handlers save the exception to a local variable, whereas the store operation at the beginning of the subroutine saves the return address to local variable.
For each catch block, a codeException(BeginPC, EndPC, HandlerPC)
is recorded,
where HandlerPC = begin(Default?Handler)
and
BeginPC = begin(tryBlock), EndPC = begin(first Handler)-1
, i.e. including the goto(A)
for each non-default handler, or both
BeginPC = begin(tryBlock), EndPC = end(last Handler)
and
BeginPC = A = begin(Tail), EndPC = end(Tail)
for the default handler.
Note that from the byte code we cannot deduce the end of the last catch clause in the absense of a finally clause. This is also manifested by the equivalence of the following two Java code fracments:
foo: { try { A; break foo; } catch(e) { B; } C; } foo: { try { A; break foo; } catch(e) { B; C; } }