Class BCMethod
- All Implemented Interfaces:
MethodBuilder
When a method is first created, it has:
- a return type
- modifiers
- a name
- an empty parameter list
- an empty throws list
- an empty statement block
MethodBuilder implementations are required to supply a way for Statements and Expressions to give them code. Most typically, they may have a stream to which their contents writes the code that is of the type to satisfy what the contents represent. MethodBuilder implementations also have to have a way to supply ClassBuilders with their code, that satisfies the type of class builder they are implemented with. This is implementation-dependent, so ClassBuilders, MethodBuilders, Statements, and Expressions all have to be of the same implementation in order to interact to generate a class.
Method Builder implementation for generating bytecode.
-
Field Summary
FieldsModifier and TypeFieldDescription(package private) final BCClass(package private) static final intCode length at which to split into sub-methods.private Conditionalprivate intprivate booleanTrue if we are currently switching control over to a sub method to avoid hitting the code generation limit of 65535 bytes per method.(package private) intMaximum stack depth seen in this method, measured in words.protected final ClassHolder(package private) CodeChunkprotected ClassMemberprivate final StringThe original name of the method, this represents how any user would call this method.(package private) final Stringprivate static final byte[]this array maps the BCExpr vm_* constants 0..6 to the expected VM type constants for the newarray instruction.(package private) BCLocalField[]Fast access for the parametes, will be null if the method has no parameters.private final String[]List of parameter types with java language class names.private intCurrent stack depth in this method, measured in words.private intPoints to the next array offset in stackTypes to be used.private Type[]Array of the current types of the values on the stack.private intprivate intHow many sub-methods we have overflowed to.(package private) static final byte -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprivate voidaddInstrCPE(short opcode, int cpe) Write a instruction that uses a constant pool entry as an operand, add a limit exceeded message if the number of constant pool entries has exceeded the limit.voidaddThrownException(String exceptionClass) a throwable can be added to the end of the list of thrownExceptions.intcallMethod(short opcode, String declaringClass, String methodName, String returnType, int numArgs) Call a method.intcallMethod(Object methodDescriptor) Call a method previously described by describeMethod().(package private) final voidcallSubMethod(BCMethod subMethod) Call a sub-method created by getNewSubMethod handling parameters correctly.voidCall super().voidCast the top stack value.voidcomplete()when the method has had all of its parameters and thrown exceptions defined, and its statement block has been completed, it can be completed and its class file information generated.voidComplete a conditional which completes the false code path.voidInitiate a conditional sequence.private voidconditionalIf(short opcode) voidInitiate a conditional sequence.(package private) ClassHolderIn their giveCode methods, the parts of the method body will want to get to the constant pool to add their constants.private Type[]describeMethod(short opcode, String declaringClass, String methodName, String returnType) Return an object that efficiently (to the implementation) describes a zero-argument method and can be used with the single argument callMethod().voiddup()Duplicate the top value on the stack.voidEnd a statement.voidgetArrayElement(int element) Pop an array refrence off the stack and push an element from that array.private voidvoidPush the contents of the described field onto the stack.voidgetField(LocalField field) Push the contents of the local field onto the stack.getName()Return the logical name of the method.(package private) final BCMethodgetNewSubMethod(String returnType, boolean withParameters) Create a sub-method from this method to allow the code builder to split a single logical method into multiple methods to avoid the 64k per-method code size limit.voidgetParameter(int id) Push a parameter value.voidgetStaticField(String declaringClass, String fieldName, String fieldType) Push the contents of the described static field onto the stack.private voidprivate voidvoidisInstanceOf(String className) Pop the top stack value and push a boolean that is the result of an instanceof check on the popped reference.voidReturn from a method, optionally with a value.private voidCheck to see if the current method byte code is nearing the limit of 65535.voidpop()Pop the top value off the stackprivate TypepopStack()voidpush(boolean value) Push a boolean constant onto the stackvoidpush(byte value) Push a byte constant onto the stackvoidpush(double value) Push a double constant onto the stackvoidpush(float value) Push a float constant onto the stackvoidpush(int value) Push a int constant onto the stackprivate voidPush an integer value.voidpush(long value) Push a long value onto the stack.voidpush(short value) Push a short constant onto the stackvoidPush a String constant onto the stackvoidpushNewArray(String className, int size) Create an array instance StackvoidpushNewComplete(int numArgs) Complete the sequence that was started with pushNewStart().voidpushNewStart(String className) Initiate a sequence that calls a constructor, equivalent to the new operator in Java.voidPush a typed null onto the stackvoidpushThis()Push this onto the stack.voidPop the top stack value and store it in the instance field of this class.voidPop the top stack value and store it in the field.voidputField(LocalField field) Upon entry the top word(s) on the stack is the value to be put into the field.private voidvoidsetArrayElement(int element) Pop an array reference off the stack, store a value in the array at the passed in offset.voidsetField(LocalField field) Set the field but don't duplicate its value so nothing is left on the stack after this call.private voidAttempt to split a large method by pushing code out to several sub-methods.voidComplete the true code path of a conditional.booleanstatementNumHitLimit(int noStatementsAdded) Tell if statement number in this method builder hits limit.voidswap()Swap the top two values on the stack.voidUpcast the top stack value.private TypevmNameDeclaringClass(String declaringClass) protected voidsets exceptionBytes to the attribute_info needed for a method's Exceptions attribute.
-
Field Details
-
CODE_SPLIT_LENGTH
static final int CODE_SPLIT_LENGTHCode length at which to split into sub-methods. Normally set to the maximim code length the JVM can support, but for testing the split code it can be reduced so that the standard tests cause some splitting. Tested with value set to 2000.- See Also:
-
cb
-
modClass
-
myReturnType
-
myName
The original name of the method, this represents how any user would call this method. -
parameters
BCLocalField[] parametersFast access for the parametes, will be null if the method has no parameters. -
parameterTypes
List of parameter types with java language class names. Can be null or zero length for no parameters. -
thrownExceptions
-
myCode
CodeChunk myCode -
myEntry
-
currentVarNum
private int currentVarNum -
statementNum
private int statementNum -
handlingOverflow
private boolean handlingOverflowTrue if we are currently switching control over to a sub method to avoid hitting the code generation limit of 65535 bytes per method. -
subMethodCount
private int subMethodCountHow many sub-methods we have overflowed to. -
stackTypes
Array of the current types of the values on the stack. A type that types up two words on the stack, e.g. double will only occupy one element in this array. This array is dynamically re-sized as needed. -
stackTypeOffset
private int stackTypeOffsetPoints to the next array offset in stackTypes to be used. Really it's the number of valid entries in stackTypes. -
maxStack
int maxStackMaximum stack depth seen in this method, measured in words. Corresponds to max_stack in the Code attribute of section 4.7.3 of the vm spec. -
stackDepth
private int stackDepthCurrent stack depth in this method, measured in words. -
condition
-
newArrayElementTypeMap
private static final byte[] newArrayElementTypeMapthis array maps the BCExpr vm_* constants 0..6 to the expected VM type constants for the newarray instruction.Because boolean was mapped to integer for general instructions, it will have to be specially matched and mapped to its value directly (4).
-
T_BOOLEAN
static final byte T_BOOLEAN- See Also:
-
-
Constructor Details
-
BCMethod
BCMethod(ClassBuilder cb, String returnType, String methodName, int modifiers, String[] parms, BCJava factory)
-
-
Method Details
-
getName
Return the logical name of the method. The current myEntry refers to the sub method we are currently overflowing to. Those sub-methods are hidden from any caller.- Specified by:
getNamein interfaceMethodBuilder
-
getParameter
public void getParameter(int id) Description copied from interface:MethodBuilderPush a parameter value.Stack ... => ...,param_value- Specified by:
getParameterin interfaceMethodBuilder- Parameters:
id- position of the parameter (zero based).
-
addThrownException
a throwable can be added to the end of the list of thrownExceptions.- Specified by:
addThrownExceptionin interfaceMethodBuilder
-
complete
public void complete()when the method has had all of its parameters and thrown exceptions defined, and its statement block has been completed, it can be completed and its class file information generated.further alterations of the method will not be reflected in the code generated for it.
- Specified by:
completein interfaceMethodBuilder
-
splitMethod
private void splitMethod()Attempt to split a large method by pushing code out to several sub-methods. Performs a number of steps.- Split at zero stack depth.
- Split at non-zero stack depth (FUTURE)
-
constantPool
ClassHolder constantPool()In their giveCode methods, the parts of the method body will want to get to the constant pool to add their constants. We really only want them treating it like a constant pool inclusion mechanism, we could write a wrapper to limit it to that. -
writeExceptions
protected void writeExceptions()sets exceptionBytes to the attribute_info needed for a method's Exceptions attribute. The ClassUtilities take care of the header 6 bytes for us, so they are not included here. See The Java Virtual Machine Specification Section 4.7.5, Exceptions attribute. -
growStack
-
growStack
-
popStack
-
copyStack
-
pushThis
public void pushThis()Description copied from interface:MethodBuilderPush this onto the stack.Stack ... => ...,this_ref- Specified by:
pushThisin interfaceMethodBuilder
-
push
public void push(byte value) Description copied from interface:MethodBuilderPush a byte constant onto the stackStack ... => ...,byte_value- Specified by:
pushin interfaceMethodBuilder
-
push
public void push(boolean value) Description copied from interface:MethodBuilderPush a boolean constant onto the stackStack ... => ...,boolean_value- Specified by:
pushin interfaceMethodBuilder
-
push
public void push(short value) Description copied from interface:MethodBuilderPush a short constant onto the stackStack ... => ...,short_value- Specified by:
pushin interfaceMethodBuilder
-
push
public void push(int value) Description copied from interface:MethodBuilderPush a int constant onto the stackStack ... => ...,int_value- Specified by:
pushin interfaceMethodBuilder
-
dup
public void dup()Description copied from interface:MethodBuilderDuplicate the top value on the stack.Stack ...,value => ...,value,value- Specified by:
dupin interfaceMethodBuilder
-
swap
public void swap()Description copied from interface:MethodBuilderSwap the top two values on the stack.Stack ...,valueA,valueB => ...,valueB,valueA- Specified by:
swapin interfaceMethodBuilder
-
push
Push an integer value. Uses the special integer opcodes for the constants -1 to 5, BIPUSH for values that fit in a byte and SIPUSH for values that fit in a short. Otherwise uses LDC with a constant pool entry.- Parameters:
value- Value to be pushedtype- Final type of the value.
-
push
public void push(long value) Push a long value onto the stack. For the values zero and one the LCONST_0 and LCONST_1 instructions are used. For values betwee Short.MIN_VALUE and Short.MAX_VALUE inclusive an byte/short/int value is pushed using push(int, Type) followed by an I2L instruction. This saves using a constant pool entry for such values. All other values use a constant pool entry. For values in the range of an Integer an integer constant pool entry is created to allow sharing with integer constants and to reduce constant pool slot entries.- Specified by:
pushin interfaceMethodBuilder
-
push
public void push(float value) Description copied from interface:MethodBuilderPush a float constant onto the stackStack ... => ...,float_value- Specified by:
pushin interfaceMethodBuilder
-
push
public void push(double value) Description copied from interface:MethodBuilderPush a double constant onto the stackStack ... => ...,double_value- Specified by:
pushin interfaceMethodBuilder
-
push
Description copied from interface:MethodBuilderPush a String constant onto the stackStack ... => ...,String_value- Specified by:
pushin interfaceMethodBuilder
-
methodReturn
public void methodReturn()Description copied from interface:MethodBuilderReturn from a method, optionally with a value. Must only be called if zero or one item exists on the stack. If the stack contains a single value then that is popped and used as the returned value.Stack value => :empty: or Stack :empty: => :empty:.- Specified by:
methodReturnin interfaceMethodBuilder
-
describeMethod
public Object describeMethod(short opcode, String declaringClass, String methodName, String returnType) Description copied from interface:MethodBuilderReturn an object that efficiently (to the implementation) describes a zero-argument method and can be used with the single argument callMethod(). Descriptions for the parameters to this method are the same as the five argument callMethod(). This allows the caller to cache frequently used methods. The returned object is only valid for use by this MethodBuilder.
This call does not affect the Stack.- Specified by:
describeMethodin interfaceMethodBuilder
-
callMethod
Description copied from interface:MethodBuilderCall a method previously described by describeMethod().static methods Stack ...,value* => [numArgs number of values will be popped] ...,return_value [void methods will not push a value] non-static methods Stack ...,ref,value* => [numArgs number of values will be popped] ...,return_value [void methods will not push a value]- Specified by:
callMethodin interfaceMethodBuilder
-
callMethod
public int callMethod(short opcode, String declaringClass, String methodName, String returnType, int numArgs) Description copied from interface:MethodBuilderCall a method. The instance (receiver or reference) for non-static methods must be pushed by the caller. The instance (for non-static) and the arguments are popped of the stack, and the return value (if any) is pushed onto the stack.
The type needs to be one of:- VMOpcode.INVOKESTATIC - call a static method
- VMOpcode.INVOKEVIRTUAL - call method declared in the class or super-class.
- VMOpcode.INVOKEINTERFACE - call a method declared in an interface
static methods Stack ...,value* => [numArgs number of values will be popped] ...,return_value [void methods will not push a value] non-static methods Stack ...,ref,value* => [numArgs number of values will be popped] ...,return_value [void methods will not push a value]
The type of the arguments to the methods must exactly match the declared types of the parameters to the methods. If a argument is of the incorrect type the caller must up cast it or down cast it.- Specified by:
callMethodin interfaceMethodBuilder- Parameters:
opcode- type of method invocationdeclaringClass- Class or interface the method is declared in. If it is a non-static method call then if declaringClass is null, the declared type is taken to be the type of the reference that will be popped.methodName- name of the methodreturnType- class name or primitive type (including "void") of the return type of the method, can not be null.numArgs- number of arguments to the method (can be 0).
-
vmNameDeclaringClass
-
callSuper
public void callSuper()Description copied from interface:MethodBuilderCall super(). Caller must only add this to a constructor.Stack ... => ...- Specified by:
callSuperin interfaceMethodBuilder
-
pushNewStart
Description copied from interface:MethodBuilderInitiate a sequence that calls a constructor, equivalent to the new operator in Java. After this call, the caller must push any arguments and then complete the construction with a call to pushNewComplete(). Only arguments to the constructor can be pushed onto the stack between the pushNewStart() and pushNewComplete() method calls.Stack ... => [unchanged] ...- Specified by:
pushNewStartin interfaceMethodBuilder- Parameters:
className- class name of object to be created.
-
pushNewComplete
public void pushNewComplete(int numArgs) Description copied from interface:MethodBuilderComplete the sequence that was started with pushNewStart(). Pop the arguments to the constructor and push the reference to the newly created object.Stack ...,value* => [numArgs number of values will be popped] ...,new_ref- Specified by:
pushNewCompletein interfaceMethodBuilder- Parameters:
numArgs- number of arguments to the constructor (can be 0).
-
upCast
Description copied from interface:MethodBuilderUpcast the top stack value. This is used for correct method resolution by upcasting method parameters. It does not put any casting code into the byte code stream. Can only be used for refrences.Stack ...,ref => ...,ref- Specified by:
upCastin interfaceMethodBuilder
-
cast
Description copied from interface:MethodBuilderCast the top stack value. Correctly down-casts a reference or casts a primitive type (e.g. int to short).Stack ...,value => ...,cast_value- Specified by:
castin interfaceMethodBuilder- Parameters:
className- type (primitive, interface or class) to cast to.
-
isInstanceOf
Description copied from interface:MethodBuilderPop the top stack value and push a boolean that is the result of an instanceof check on the popped reference.Stack ...,ref => ...,boolean_value.- Specified by:
isInstanceOfin interfaceMethodBuilder
-
pushNull
Description copied from interface:MethodBuilderPush a typed null onto the stackStack ... => ...,null- Specified by:
pushNullin interfaceMethodBuilder
-
getField
Description copied from interface:MethodBuilderPush the contents of the local field onto the stack. This call pushes the this instance required to access the field itself.Stack ... => ...,field_value- Specified by:
getFieldin interfaceMethodBuilder
-
getField
Description copied from interface:MethodBuilderPush the contents of the described field onto the stack. This call requires the instance (reference) to be pushed by the caller.Stack ...,field_ref => ...,field_value- Specified by:
getFieldin interfaceMethodBuilder
-
getStaticField
Push the contents of the described static field onto the stack.- Specified by:
getStaticFieldin interfaceMethodBuilder
-
getField
-
setField
Set the field but don't duplicate its value so nothing is left on the stack after this call.- Specified by:
setFieldin interfaceMethodBuilder
-
putField
Upon entry the top word(s) on the stack is the value to be put into the field. Ie. we haveword
Before the call we needword this word
word2,word1 -> word2, word1, word2 So that we are left with word after the put.- Specified by:
putFieldin interfaceMethodBuilder
-
putField
Pop the top stack value and store it in the instance field of this class.- Specified by:
putFieldin interfaceMethodBuilder
-
putField
-
putField
Pop the top stack value and store it in the field. This call requires the instance to be pushed by the caller.- Specified by:
putFieldin interfaceMethodBuilder
-
conditionalIfNull
public void conditionalIfNull()Description copied from interface:MethodBuilderInitiate a conditional sequence. The top value on the stack (a reference) is popped and compared to 'null'. If the value is null then the code following this call until the startElseCode() will be executed at runtime, otherwise the code following startElseCode() until the completeConditional() is called.
E.g.mb.callMethod(...); // pushes an object onto the stack mb.conditionalIfNull(); mb.push(3); mb.startElseCode(); mb.push(5); mb.completeConditional(); // at this point 3 or 5 will be on the stack
Each path through the ?: statement must leave the stack at the same depth as the other.
If the if or else code pops values from the stack that were before the conditional value, then they must use the same number of values from the stack.Stack ...,ref => ....- Specified by:
conditionalIfNullin interfaceMethodBuilder
-
conditionalIf
public void conditionalIf()Description copied from interface:MethodBuilderInitiate a conditional sequence. The top value on the stack must be a boolean and will be popped. If it is true then the code following this call until the startElseCode() will be executed at runtime, otherwise the code following startElseCode() until the completeConditional() is called. See conditionalIfNull() for example and restrictions.Stack ...,boolean_value => ....- Specified by:
conditionalIfin interfaceMethodBuilder
-
conditionalIf
private void conditionalIf(short opcode) -
startElseCode
public void startElseCode()Description copied from interface:MethodBuilderComplete the true code path of a conditional.- Specified by:
startElseCodein interfaceMethodBuilder
-
completeConditional
public void completeConditional()Description copied from interface:MethodBuilderComplete a conditional which completes the false code path.- Specified by:
completeConditionalin interfaceMethodBuilder
-
pop
public void pop()Description copied from interface:MethodBuilderPop the top value off the stackStack ..., value => ....- Specified by:
popin interfaceMethodBuilder
-
endStatement
public void endStatement()Description copied from interface:MethodBuilderEnd a statement. Pops the top-word of the stack, if any. Must only be called if zero or one item exists on the stack.Stack value => :empty: or Stack :empty: => :empty:.- Specified by:
endStatementin interfaceMethodBuilder
-
getArrayElement
public void getArrayElement(int element) Description copied from interface:MethodBuilderPop an array refrence off the stack and push an element from that array.Stack ...,array_ref => ...,value- Specified by:
getArrayElementin interfaceMethodBuilder- Parameters:
element- Offset into the array (zero based)
-
setArrayElement
public void setArrayElement(int element) Description copied from interface:MethodBuilderPop an array reference off the stack, store a value in the array at the passed in offset.Stack ...,array_ref, value => ...- Specified by:
setArrayElementin interfaceMethodBuilder- Parameters:
element- Offset into the array (zero based)
-
pushNewArray
Create an array instance Stack ... => ...,arrayref- Specified by:
pushNewArrayin interfaceMethodBuilder- Parameters:
className- - type of array.size- - number of elements in the array
-
addInstrCPE
private void addInstrCPE(short opcode, int cpe) Write a instruction that uses a constant pool entry as an operand, add a limit exceeded message if the number of constant pool entries has exceeded the limit. -
statementNumHitLimit
public boolean statementNumHitLimit(int noStatementsAdded) Tell if statement number in this method builder hits limit. This method builder keeps a counter of how many statements are added to it. Caller should call this function every time it tries to add a statement to this method builder (counter is increased by 1), then the function returns whether the accumulated statement number hits a limit. The reason of doing this is that Java compiler has a limit of 64K code size for each method. We might hit this limit if an extremely long insert statement is issued, for example (see beetle 4293). Counting statement number is an approximation without too much overhead.- Specified by:
statementNumHitLimitin interfaceMethodBuilder
-
overflowMethodCheck
private void overflowMethodCheck()Check to see if the current method byte code is nearing the limit of 65535. If it is start overflowing to a new method.Overflow is handled for a method named e23 as:
public Object e23() { ... existing code // split point return e23_0(); } private Object e23_0() { ... first set overflowed code // split point return e23_1(); } private Object e23_1() { ... second set overflowed code // method complete return result; }These overflow methods are hidden from the code using this MethodBuilder, it continues to think that it is building a single method with the original name.
Restrictions:- Only handles methods with no arguments
- Stack depth must be zero
-
getNewSubMethod
Create a sub-method from this method to allow the code builder to split a single logical method into multiple methods to avoid the 64k per-method code size limit. The sub method with inherit the thrown exceptions of this method.- Parameters:
returnType- Return type of the new methodwithParameters- True to define the method with matching parameters false to define it with no parameters.- Returns:
- A valid empty sub method.
-
callSubMethod
Call a sub-method created by getNewSubMethod handling parameters correctly.
-