class CodeUnit extends BytecodeContainer implements ExpressionParserTokenTypes
A code unit generally has a data type associated with it, though this is not strictly necessary in all cases. The data type generally corresponds with the type of data last left on the stack by the code unit's instructions. The bytecode assembler often refers to a code unit's data type to determine how this code unit can be nested or chained with other code units, and whether any additional instructions are necessary to generate another, target result type.
A code unit can contain a simple list of instructions and/or nested code
units, and may optionally define a single CodeUnit.BranchData
object. Branch data is used when the purpose of the code unit is to jump
to another instruction in the method, based upon some test done on the top
one or two runtime stack values (or unconditionally, in the case of the
GOTO
branch).
Some branches require obsolete stack values to be popped off the stack
before jumping to another instruction. As a rule, the height of the stack
just before a jump occurs must be the same as it would be had the
destination instruction been reached by any other means (e.g., via linear
execution of instructions). To meet this requirement, some code units
are defined as stack markers, and others are defined as
stack poppers. A combination of stack marker and stack popper
code units are used by the bytecode assembler to ensure the proper
pop
and/or pop2
instructions are added before
a branching instruction jumps to another location. This fixup is done
after the primary assembly of functional bytecode instructions, in a
final compilation step using CodeAttribute.fixupStack()
. This
invocation eventually resolves down to this class' fixupStack(java.util.Stack)
method, which does the real work of inserting the necessary pops.
Modifier and Type | Class and Description |
---|---|
protected class |
CodeUnit.BranchData
This class encapsulates information necessary to branch execution
of the JVM from one bytecode instruction to another in the bytecode
array.
|
Modifier and Type | Field and Description |
---|---|
private CodeUnit.BranchData |
branchData
Data associated with a logic branch
|
protected java.util.List |
contents
Inner code units and instructions
|
private java.lang.Class |
dataType
The data type associated with this code unit
|
private boolean |
stackMarker
Indicates a special stack-management code unit
|
private boolean |
stackPopper
Result type of this code unit
|
length, offset
AND, ASSIGN, BIT_AND, BIT_COMP, BIT_OR, BIT_XOR, BOOL_FALSE, BOOL_TRUE, CAST, COMMA, DEC_LITERAL, DIGIT, DIVIDE, DOT, DSTRING, EOF, EQUALS, GOTO, GT, GTE, HASH, HEX_LITERAL, HEXDIGIT, IDENTITY, IS_NULL, LETTER, LPARENS, LSHIFT, LT, LTE, METH_BOOLEAN, METH_DOUBLE, METH_INT, METH_LONG, METH_OBJ, MINUS, MODULO, MULTIPLY, NOT, NOT_EQ, NOT_NULL, NULL, NULL_TREE_LOOKAHEAD, NUM_LITERAL, OR, PLUS, POSPARM, RPARENS, RSHIFT, SSTRING, STRING, SYM_CHAR, SYMBOL, UN_MINUS, VALID_SYM_CHAR, WS, ZRSHIFT
_aastore, _aconst_null, _aload_0, _aload_1, _aload_2, _aload_3, _anewarray, _areturn, _astore_1, _astore_2, _astore_3, _checkcast, _d2i, _d2l, _dadd, _dcmpg, _dconst_0, _dconst_1, _ddiv, _dmul, _dneg, _drem, _dreturn, _dsub, _dup, _getfield, _goto, _i2d, _i2l, _iadd, _iand, _iconst_0, _iconst_1, _iconst_2, _iconst_3, _iconst_4, _iconst_5, _idiv, _if_icmpeq, _if_icmpge, _if_icmpgt, _if_icmple, _if_icmplt, _if_icmpne, _ifeq, _ifge, _ifgt, _ifle, _iflt, _ifne, _ifnonnull, _ifnull, _imul, _ineg, _invokeinterface, _invokespecial, _invokestatic, _invokevirtual, _ior, _irem, _ireturn, _ishl, _ishr, _isub, _iushr, _ixor, _l2d, _l2i, _ladd, _land, _lcmp, _lconst_0, _lconst_1, _ldc_w, _ldc2_w, _ldiv, _lmul, _lneg, _lor, _lrem, _lshl, _lshr, _lsub, _lushr, _lxor, _new, _pop, _pop2, _return, _swap, CLASS_COMPILEDEXPRESSION, METHDESC_EXECUTE, METHNAME_EXECUTE, METHOD_INIT
Constructor and Description |
---|
CodeUnit()
Default constructor.
|
CodeUnit(boolean condition,
ExtraAst target,
int type,
boolean binary)
This constructor is used to create a code unit containing a
CodeUnit.BranchData object which branches to the specified destination
under the specified condition. |
CodeUnit(java.lang.Class dataType)
Constructor which assigns a data type to the resulting code unit.
|
Modifier and Type | Method and Description |
---|---|
void |
addBranchInstruction()
Add the branch instruction of a branching code unit to the end of the
current contents.
|
(package private) void |
addCodeUnit(CodeUnit unit)
This method adds the specified code unit to the end of this code unit.
|
(package private) void |
addInstruction(Instruction instruc)
This method adds the specified instruction to the end of this code
unit.
|
(package private) void |
addInstruction(int opCode)
Convenience method to add a new instruction.
|
void |
fixupBranchOffset()
This method is called after the final offsets for each bytecode
instruction have been assigned.
|
(package private) void |
fixupStack(java.util.Stack stack)
This method checks whether this code unit is designated as a
stackPopper . |
(package private) java.lang.Class |
getDataType()
Return the data type associated with this code unit.
|
int |
getLength()
Return the length of this code unit.
|
int |
layout(int offset)
This method assigns the specified offset address to the beginning of
this code unit and assigns the appropriate addresses to each
instruction and nested code unit inside this one.
|
void |
modifyStackDepth(Compiler compiler)
Each unit of code may have some impact on the maximum depth of the
JVM's runtime operand stack.
|
(package private) void |
setDataType(java.lang.Class dataType)
Set the data type associated with this code unit.
|
(package private) void |
setStackMarker(boolean stackMarker)
Used to indicate that this code unit defines a stack-managing scope,
meaning it contains a
goto instruction. |
(package private) void |
setStackPopper(boolean stackPopper)
Used to indicate that this code unit cooperates with code units of
type
stackMarker to clear the stack of irrelevant data
values before a branch instruction. |
java.lang.String |
toString()
Returns a string representation of this object, which is a line
separated listing of this unit's contents.
|
void |
write(java.io.DataOutput out)
This method writes the bytecode contents of this code unit to the
specified output stream.
|
getOffset
protected java.util.List contents
private CodeUnit.BranchData branchData
private boolean stackMarker
private boolean stackPopper
private java.lang.Class dataType
CodeUnit()
null
.CodeUnit(java.lang.Class dataType)
dataType
- Data type to be associated with the new code unit.CodeUnit(boolean condition, ExtraAst target, int type, boolean binary)
CodeUnit.BranchData
object which branches to the specified destination
under the specified condition.condition
- Condition under which code unit branches to
target
's code unit. This may be ignored,
depending upon the type
specified. For
instance, a type GOTO
branch is unconditional,
and therefore does not use condition
as a
branch trigger.target
- An AST which contains information about the destination of
the branch instruction implied by type
and
condition
. This AST will eventually have a
CodeUnit
object stored in its extra
field, which represents the destination of this
code unit's branch instruction.type
- Type of branch logic; indicates which bytecode instruction
is used, depending also on condition
.binary
- true
if this code unit manages a binary operation
(i.e., requires two operands from the runtime stack). If
false
, the branch will only consider a single
stack operand (unary), or no operands (unconditional),
depending upon the type
parameter.ExpressionException
- if an invalid branching condition is detected.void addInstruction(Instruction instruc)
instruc
- Instruction to be added.void addInstruction(int opCode)
opCode
- Operation code of the bytecode instruction to add.void addCodeUnit(CodeUnit unit)
unit
- Code unit to be added.java.lang.Class getDataType()
void setDataType(java.lang.Class dataType)
dataType
- Data type.void setStackMarker(boolean stackMarker)
goto
instruction. Before the
goto
is executed, the runtime stack must be rid of any
values which will no longer be relevant at the destination bytecode.
bytecode. CodeUnits of type stackPopper
will add
instructions to pop the appropriate number of values off the stack
before the goto. The "appropriate" number of values to be popped is
determined by the stack-managing scope of a code unit. Only as many
values as have been pushed within this scope at the time of goto will
be popped.stackMarker
- true
to indicate that this code unit defines a
stack-managing scope as described above; else
false
. The default value of the stack marker
attribute is false
, so there is typically no
need to call this method with a value of false
.setStackPopper(boolean)
,
fixupStack(java.util.Stack)
void setStackPopper(boolean stackPopper)
stackMarker
to clear the stack of irrelevant data
values before a branch instruction. CodeUnits of this type will add
instructions to pop the appropriate number of values off the stack
before the goto. The "appropriate" number of values to be popped is
determined by the stack-managing scope of a code unit. Only as many
values as have been pushed within that scope at the time of goto will
be popped.stackPopper
- true
to indicate that this code unit should
add pop/pop2 instructions to clear the stack of irrelevant
values within a stack marker scope. false
indicates a normal code unit.setStackMarker(boolean)
,
fixupStack(java.util.Stack)
public int getLength()
getLength
in class BytecodeContainer
public void modifyStackDepth(Compiler compiler)
modifyStackDepth
in class BytecodeContainer
compiler
- Expression compiler which maintains stack depth information.public int layout(int offset)
layout
in class BytecodeContainer
offset
- Offset address of this code unit within the bytecode array
for the method currently being compiled.offset
and
adding the width of this code unit to that address.void fixupStack(java.util.Stack stack)
stackPopper
. Code units of this type are placed within
code units which branch when an object reference is null
,
immediately prior to a goto
instruction. To avoid verify
errors at load time, we must ensure that at the time the branch is
executed, the stack depth must be exactly what it was when this code
unit was entered. If it is not, we insert the appropriate number of
pop
and/or pop2
instructions before the
goto
to fix up the stack.
If this code unit is not a stackPopper, this method is called
recursively, on all BytecodeContainer
s found within this
code unit.
fixupStack
in class BytecodeContainer
stack
- A stack which represents the state of the runtime stack at
the time this code unit will be executed in the final,
compiled method.public void addBranchInstruction()
BranchData
object.java.lang.NullPointerException
- if this code unit has not defined BranchData
object.public void fixupBranchOffset()
fixupBranchOffset
in class BytecodeContainer
public void write(java.io.DataOutput out) throws java.io.IOException
write
in interface WritableData
out
- Output stream to which data is written.java.io.IOException
- if any error occurs during writing.public java.lang.String toString()
toString
in class java.lang.Object