Modifier and Type | Field and Description |
---|---|
pack-priv static final short[] | |
pack-priv static final short[] | |
pack-priv static final short[][][] | |
pack-priv final BCClass | cb
The class we are generating code for, used to indicate that some limit was hit during code generation. |
private static final int | CODE_OFFSET
Starting point of the byte code stream in the underlying stream/array. |
private final ClassFormatOutput | |
pack-priv static final short[] | |
pack-priv static final short[] | |
private static final byte[] | NS
Constant used by OPCODE_ACTION to the opcode is not yet supported. |
private static final byte[][] | OPCODE_ACTION
Array that provides two pieces of information about each VM opcode. |
private final int | pcDelta
The delta between cout.size() and the pc. |
private static final byte[] | push1_1i
Constant used by OPCODE_ACTION to represent the common action of push one word, 1 byte for the instruction. |
private static final byte[] | push2_1i
Constant used by OPCODE_ACTION to represent the common action of push two words, 1 byte for the instruction. |
pack-priv static final short[] | |
pack-priv static final short[] | |
pack-priv static final short[] | |
private static final byte | VARIABLE_STACK
Value for OPCODE_ACTION[opcode][0] to represent the number of words popped or pushed in variable. |
Access | Constructor and Description |
---|---|
pack-priv | |
private |
Modifier and Type | Method and Description |
---|---|
pack-priv void | |
pack-priv void | addInstrCPE(short opcode, int cpeNum)
This takes an instruction that has a narrow and a wide form for CPE access, and generates accordingly the right one. |
pack-priv void | |
pack-priv void | |
pack-priv void | addInstrU2U1U1(short opcode, int operand1, short operand2, short operand3)
For adding an instruction with 3 operands, a U2 and two U1's. |
pack-priv void | |
pack-priv void | addInstrWide(short opcode, int varNum)
This takes an instruction that can be wrapped in a wide for large variable #s and does so. |
pack-priv void | complete(BCMethod mb, ClassHolder ch, ClassMember method, int maxStack, int maxLocals)
wrap up the entry and stuff it in the class, now that it holds all of the instructions and the exception table. |
private int[] | Returns: Null if the opcode is not the start of a conditional otherwise the array of values.Find the limits of a conditional block starting at the instruction with the given opcode at the program counter pc. |
private int | findMaxStack(ClassHolder ch, int pc, int codeLength)
For a block of byte code starting at program counter pc for codeLength bytes return the maximum stack value, assuming a initial stack depth of zero. |
private void | fixLengths(BCMethod mb, int maxStack, int maxLocals, int codeLength)
now that we have codeBytes, fix the lengths fields in it to reflect what was stored. |
private static int | getDescriptorWordCount(String vmDescriptor)
Get the word count for a type descriptor in the format of the virual machine. |
pack-priv short | |
pack-priv int | |
private String | getTypeDescriptor(ClassHolder ch, int pc)
Get the type descriptor in the virtual machine format for the type defined by the constant pool index for the instruction at pc. |
private int | |
private int | |
private int | getVariableStackDelta(ClassHolder ch, int pc, int opcode)
Get the number of words pushed (positive) or popped (negative) by this instruction. |
pack-priv CodeChunk | insertCodeSpace(int pc, int additionalBytes)
Insert room for byteCount bytes after the instruction at pc and prepare to replace the instruction at pc. |
private static int | |
private static boolean | Returns: true for is a return instruction, false otherwise.opcode to be checked opcode)See if the opcode is a return instruction. |
private void | |
private static int | parameterWordCount(String methodDescriptor)
Calculate the number of stack words in the arguments pushed for this method descriptor. |
private int | removePushedCode(BCMethod
My method mb, ClassHolder My class ch, BCMethod Sub-method code was pushed into subMethod, final int Program counter the split started at split_pc, final int Length of code split splitLength)Remove a block of code from this method that was pushed into a sub-method and call the sub-method. |
private int | splitCodeIntoSubMethod(BCMethod
My method mb, ClassHolder My class ch, BCMethod Sub-method code was pushed into subMethod, final int Program counter the split started at split_pc, final int Length of code split splitLength)Split a block of code from this method into a sub-method and call it. |
pack-priv final int | splitExpressionOut(final BCMethod mb, final ClassHolder ch, final int optimalMinLength, final int maxStack)
Split an expression out of a large method into its own sub-method. |
private static int | |
pack-priv final int | splitZeroStack(BCMethod
Method for this chunk. mb, ClassHolder Class definition ch, final int split_pc, final int minimum length required for split optimalMinLength)Attempt to split the current method by pushing a chunk of its code into a sub-method. |
private int | stackWordDelta(ClassHolder ch, int pc, short opcode)
Return the number of stack words pushed (positive) or popped (negative) by this instruction. |
private BCMethod | startSubMethod(BCMethod mb, String returnType, int split_pc, int blockLength)
Start a sub method that we will split the portion of our current code to, starting from start_pc and including codeLength bytes of code. |
private boolean |
ARRAY_ACCESS | back to summary |
---|---|
pack-priv static final short[] ARRAY_ACCESS |
ARRAY_STORE | back to summary |
---|---|
pack-priv static final short[] ARRAY_STORE |
CAST_CONVERSION_INFO | back to summary |
---|---|
pack-priv static final short[][][] CAST_CONVERSION_INFO |
cb | back to summary |
---|---|
pack-priv final BCClass cb The class we are generating code for, used to indicate that some limit was hit during code generation. |
CODE_OFFSET | back to summary |
---|---|
private static final int CODE_OFFSET Starting point of the byte code stream in the underlying stream/array. |
cout | back to summary |
---|---|
private final ClassFormatOutput cout |
LOAD_VARIABLE | back to summary |
---|---|
pack-priv static final short[] LOAD_VARIABLE |
LOAD_VARIABLE_FAST | back to summary |
---|---|
pack-priv static final short[] LOAD_VARIABLE_FAST |
NS | back to summary |
---|---|
private static final byte[] NS Constant used by OPCODE_ACTION to the opcode is not yet supported. |
OPCODE_ACTION | back to summary |
---|---|
private static final byte[][] OPCODE_ACTION Array that provides two pieces of information about each VM opcode. Each opcode has a two byte array. The first element in the array [0] is the number of stack words (double/long count as two) pushed by the opcode. Will be negative if the opcode pops values. The second element in the array [1] is the number of bytes in the instruction stream that this opcode's instruction takes up, including the opocode. |
pcDelta | back to summary |
---|---|
private final int pcDelta The delta between cout.size() and the pc. For an initial code chunk this is -8 (CODE_OFFSET) since 8 bytes are written. For a nested CodeChunk return by insertCodeSpace the delta corresponds to the original starting pc.
|
push1_1i | back to summary |
---|---|
private static final byte[] push1_1i Constant used by OPCODE_ACTION to represent the common action of push one word, 1 byte for the instruction. |
push2_1i | back to summary |
---|---|
private static final byte[] push2_1i Constant used by OPCODE_ACTION to represent the common action of push two words, 1 byte for the instruction. |
RETURN_OPCODE | back to summary |
---|---|
pack-priv static final short[] RETURN_OPCODE |
STORE_VARIABLE | back to summary |
---|---|
pack-priv static final short[] STORE_VARIABLE |
STORE_VARIABLE_FAST | back to summary |
---|---|
pack-priv static final short[] STORE_VARIABLE_FAST |
VARIABLE_STACK | back to summary |
---|---|
private static final byte VARIABLE_STACK Value for OPCODE_ACTION[opcode][0] to represent the number of words popped or pushed in variable. |
CodeChunk | back to summary |
---|---|
pack-priv CodeChunk(BCClass cb) |
CodeChunk | back to summary |
---|---|
private CodeChunk(CodeChunk main, int pc, int byteCount) Return a CodeChunk that has limited visibility into this CodeChunk. Used when a caller needs to insert instructions into an existing stream. |
addInstr | back to summary |
---|---|
pack-priv void addInstr(short opcode) Add an instruction that has no operand. All opcodes are 1 byte large. |
addInstrCPE | back to summary |
---|---|
pack-priv void addInstrCPE(short opcode, int cpeNum) This takes an instruction that has a narrow and a wide form for CPE access, and generates accordingly the right one. We assume the narrow instruction is what we were given, and that the wide form is the next possible instruction. |
addInstrU1 | back to summary |
---|---|
pack-priv void addInstrU1(short opcode, int operand) Add an instruction that has an 8 bit operand. |
addInstrU2 | back to summary |
---|---|
pack-priv void addInstrU2(short opcode, int operand) Add an instruction that has a 16 bit operand. |
addInstrU2U1U1 | back to summary |
---|---|
pack-priv void addInstrU2U1U1(short opcode, int operand1, short operand2, short operand3) For adding an instruction with 3 operands, a U2 and two U1's. So far, this is used by VMOpcode.INVOKEINTERFACE. |
addInstrU4 | back to summary |
---|---|
pack-priv void addInstrU4(short opcode, int operand) Add an instruction that has a 32 bit operand. |
addInstrWide | back to summary |
---|---|
pack-priv void addInstrWide(short opcode, int varNum) This takes an instruction that can be wrapped in a wide for large variable #s and does so. |
complete | back to summary |
---|---|
pack-priv void complete(BCMethod mb, ClassHolder ch, ClassMember method, int maxStack, int maxLocals) wrap up the entry and stuff it in the class, now that it holds all of the instructions and the exception table. |
findConditionalPCs | back to summary |
---|---|
private int[] findConditionalPCs(int pc, short opcode) Find the limits of a conditional block starting at the instruction with the given opcode at the program counter pc.
Returns a six element integer array of program counters and lengths.
|
findMaxStack | back to summary |
---|---|
private int findMaxStack(ClassHolder ch, int pc, int codeLength) For a block of byte code starting at program counter pc for codeLength bytes return the maximum stack value, assuming a initial stack depth of zero. |
fixLengths | back to summary |
---|---|
private void fixLengths(BCMethod mb, int maxStack, int maxLocals, int codeLength) now that we have codeBytes, fix the lengths fields in it to reflect what was stored. Limits checked here are from these sections of the JVM spec.
|
getDescriptorWordCount | back to summary |
---|---|
private static int getDescriptorWordCount(String vmDescriptor) Get the word count for a type descriptor in the format of the virual machine. For a method this returns the the word count for the return type. |
getOpcode | back to summary |
---|---|
pack-priv short getOpcode(int pc) Return the opcode at the given pc. |
getPC | back to summary |
---|---|
pack-priv int getPC() Get the current program counter |
getTypeDescriptor | back to summary |
---|---|
private String getTypeDescriptor(ClassHolder ch, int pc) Get the type descriptor in the virtual machine format for the type defined by the constant pool index for the instruction at pc. |
getU2 | back to summary |
---|---|
private int getU2(int pc) Get the unsigned short value for the opcode at the program counter pc. |
getU4 | back to summary |
---|---|
private int getU4(int pc) Get the unsigned 32 bit value for the opcode at the program counter pc. |
getVariableStackDelta | back to summary |
---|---|
private int getVariableStackDelta(ClassHolder ch, int pc, int opcode) Get the number of words pushed (positive) or popped (negative) by this instruction. The instruction is a get/put field or a method call, thus the size of the words is defined by the field or method being access. |
insertCodeSpace | back to summary |
---|---|
pack-priv CodeChunk insertCodeSpace(int pc, int additionalBytes) Insert room for byteCount bytes after the instruction at pc and prepare to replace the instruction at pc. The instruction at pc is not modified by this call, space is allocated after it. The newly inserted space will be filled with NOP instructions. Returns a CodeChunk positioned at pc and available to write instructions upto (byteCode + length(existing instruction at pc) bytes. This chunk is left correctly positioned at the end of the code stream, ready to accept more code. Its pc will have increased by additionalBytes. It is the responsibility of the caller to patch up any branches or gotos. |
instructionLength | back to summary |
---|---|
private static int instructionLength(short opcode) Return the complete instruction length for the passed in opcode. This will include the space for the opcode and its operand. |
isReturn | back to summary |
---|---|
private static boolean isReturn(short opcode) See if the opcode is a return instruction.
|
limitHit | back to summary |
---|---|
private void limitHit(IOException ioe) Assume an IOException means some limit of the class file format was hit |
parameterWordCount | back to summary |
---|---|
private static int parameterWordCount(String methodDescriptor) Calculate the number of stack words in the arguments pushed for this method descriptor. |
removePushedCode | back to summary |
---|---|
private int removePushedCode(BCMethod mb, ClassHolder ch, BCMethod subMethod, final int split_pc, final int splitLength) Remove a block of code from this method that was pushed into a sub-method and call the sub-method. Returns the pc of this method just after the call to the sub-method.
|
splitCodeIntoSubMethod | back to summary |
---|---|
private int splitCodeIntoSubMethod(BCMethod mb, ClassHolder ch, BCMethod subMethod, final int split_pc, final int splitLength) Split a block of code from this method into a sub-method and call it. Returns the pc of this method just after the call to the sub-method.
|
splitExpressionOut | back to summary |
---|---|
pack-priv final int splitExpressionOut(final BCMethod mb, final ClassHolder ch, final int optimalMinLength, final int maxStack) Split an expression out of a large method into its own sub-method. Method call expressions are of the form:
This method will split out such expressions in sub-methods and replace the original code with a call to that submethod.
Looking at the byte code for such calls they would look like
(for an example three argument method):
Because the VM is a stack machine the original byte code sequences are self contained. The stack at the start of is sequence is N and at the end (after the method call) will be:
The code is self contained because in general the byte code for the arguments will push and pop values but never drop below the stack value at the start of the byte code sequence. E.g. in the examples the stack before the first arg will be N+1 (the objectref for the method call) and at the end of the byte code for arg1 will be N+2 or N+3 depending on if arg1 is a single or double word argument. During the execution of the byte code the stack may have had many arguments pushed and popped, but will never have dropped below N+1. Thus the code for arg1 is independent of the stack's previous values and is self contained. This self-containment then extends to all the arguements, the method call itself and pushing the objectref for the method call, thus the complete sequence is self-contained. The self-containment breaks in a few cases, take the simple method call this.method(3), the byte code for this could be:
push3 this swap invoke
In this case the byte code for arg1 (swap) is not self-contained
and relies on earlier stack values.
How to identify "self-contained blocks of code".
WORK IN PROGRESS - Incremental development
|
splitMinLength | back to summary |
---|---|
private static int splitMinLength(BCMethod mb) Minimum split length for a sub-method. If the number of
instructions to call the sub-method exceeds the length
of the sub-method, then there's no point splitting.
The number of bytes in the code stream to call
a generated sub-method can take is based upon the number of method args.
A method can have maximum of 255 words of arguments (section 4.10 JVM spec)
which in the worst case would be 254 (one-word) parameters
and this. For a sub-method the arguments will come from the
parameters to the method, i.e. ALOAD, ILOAD etc.
|
splitZeroStack | back to summary |
---|---|
pack-priv final int splitZeroStack(BCMethod mb, ClassHolder ch, final int split_pc, final int optimalMinLength) Attempt to split the current method by pushing a chunk of its code into a sub-method. The starting point of the split (split_pc) must correspond to a stack depth of zero. It is the reponsibility of the caller to ensure this. Split is only made if there exists a chunk of code starting at pc=split_pc, whose stack depth upon termination is zero. The method will try to split a code section greater than optimalMinLength but may split earlier if no such block exists. The method is aimed at splitting methods that contain many independent statements. If a split is possible this method will perform the split and create a void sub method, and move the code into the sub-method and setup this method to call the sub-method before continuing. This method's max stack and current pc will be correctly set as though the method had just been created.
|
stackWordDelta | back to summary |
---|---|
private int stackWordDelta(ClassHolder ch, int pc, short opcode) Return the number of stack words pushed (positive) or popped (negative) by this instruction. |
startSubMethod | back to summary |
---|---|
private BCMethod startSubMethod(BCMethod mb, String returnType, int split_pc, int blockLength) Start a sub method that we will split the portion of our current code to, starting from start_pc and including codeLength bytes of code. Return a BCMethod obtained from BCMethod.getNewSubMethod with the passed in return type and same parameters as mb if the code block to be moved uses parameters. |
usesParameters | back to summary |
---|---|
private boolean usesParameters(BCMethod mb, int pc, int codeLength) Does a section of code use parameters. Any load, exception ALOAD_0 in an instance method, is seen as using parameters, as this complete byte code implementation does not use local variables. |