/* * Copyright 2004-2010 Brian S O'Neill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.cojen.classfile; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.MissingResourceException; /** * CodeAssembler is a high-level interface for assembling Java Virtual Machine * byte code. It can also be used as a visitor to a disassembler. * * @author Brian S O'Neill */ public interface CodeAssembler { /** Convert floating point values as normal */ public final static int CONVERT_FP_NORMAL = 0; /** Convert floating point values as bits (NaN is canonicalized) */ public final static int CONVERT_FP_BITS = 1; /** Convert floating point values as raw bits */ public final static int CONVERT_FP_RAW_BITS = 2; /** * Returns the amount of parameters that are accepted by the method being * built, not including any "this" reference. */ int getParameterCount(); /** * Returns a specific parameter, whose index lies within 0 to * getParameterCount() - 1. The names of the LocalVariables returned by * this method are initially set to null. It is encouraged that a name be * provided. */ LocalVariable getParameter(int index) throws IndexOutOfBoundsException; /** * Creates a LocalVariable reference from a name and type. Although name * is optional, it is encouraged that a name be provided. Names do not * need to be unique. * * @param name Optional name for the LocalVariable. * @param type The type of data that the requested LocalVariable can * store. */ LocalVariable createLocalVariable(String name, TypeDesc type); /** * Creates a label, whose location must be set. To create a label and * locate it here, the following example demonstrates how the call to * setLocation can be chained: * * <pre> * CodeBuilder builder; * ... * Label label = builder.createLabel().setLocation(); * </pre> * * @see Label#setLocation */ Label createLabel(); /** * Sets up an exception handler located here, the location of the next * code to be generated. * * @param startLocation Location at the start of the section of * code to be wrapped by an exception handler. * @param endLocation Location directly after the end of the * section of code. * @param catchClassName The class name of exception to be caught; * if null, then catch every object. */ void exceptionHandler(Location startLocation, Location endLocation, String catchClassName); /** * Map the location of the next code to be generated to a line number * in source code. This enables line numbers in a stack trace from the * generated code. */ void mapLineNumber(int lineNumber); /** * Allows code to disassembled and copied straight in. The code object * passed in must have a single method named "define" whose arguments match * the type and order of values expected on the operand stack. If a return * value is provided, it will pushed onto the stack. The define method can * have any access modifier. * * @throws IllegalArgumentException if define method not found, or if * multiple are found * @throws MissingResourceException if define code not found */ void inline(Object code) throws IllegalArgumentException, MissingResourceException; // load-constant-to-stack style instructions /** * Generates code that loads a null reference onto the stack. */ void loadNull(); /** * Generates code that loads a constant string value onto the stack. If * value is null, the generated code loads a null onto the stack. Strings * that exceed 65535 UTF encoded bytes in length are loaded by creating a * StringBuffer (or a StringBuilder), appending substrings, and then * converting it to a String. */ void loadConstant(String value); /** * Generates code that loads a constant class value onto the stack. * If value is null, the generated code loads a null onto the stack. * * @param type any object or primitive type * @throws IllegalStateException if class file target version does not * support this feature */ void loadConstant(TypeDesc type) throws IllegalStateException; /** * Generates code that loads a constant boolean value onto the stack. */ void loadConstant(boolean value); /** * Generates code that loads a constant int, char, short or byte value * onto the stack. */ void loadConstant(int value); /** * Generates code that loads a constant long value onto the stack. */ void loadConstant(long value); /** * Generates code that loads a constant float value onto the stack. */ void loadConstant(float value); /** * Generates code that loads a constant double value onto the stack. */ void loadConstant(double value); // load-local-to-stack style instructions /** * Generates code that loads a local variable onto the stack. Parameters * passed to a method and the "this" reference are all considered local * variables, as well as any that were created. * * @param local The local variable reference */ void loadLocal(LocalVariable local); /** * Loads a reference to "this" onto the stack. Static methods have no * "this" reference, and an exception is thrown when attempting to * generate "this" in a static method. */ void loadThis(); // store-from-stack-to-local style instructions /** * Generates code that pops a value off of the stack into a local variable. * Parameters passed to a method and the "this" reference are all * considered local variables, as well as any that were created. * * @param local The local variable reference * @see #getParameter * @see #createLocalVariable */ void storeLocal(LocalVariable local); // load-to-stack-from-array style instructions /** * Generates code that loads a value from an array. An array * reference followed by an index must be on the stack. The array * reference and index are replaced by the value retrieved from the array * after the generated instruction has executed. * <p> * The type doesn't need to be an exact match for objects. * TypeDesc.OBJECT works fine for all objects. For primitive types, use * the appropriate TypeDesc. For an int, the type is TypeDesc.INT. * * @param type The type of data stored in the array. */ void loadFromArray(TypeDesc type); // store-to-array-from-stack style instructions /** * Generates code that stores a value to an array. An array * reference followed by an index, followed by a value (or two if a long * or double) must be on the stack. All items on the stack are gone * after the generated instruction has executed. * <p> * The type doesn't need to be an exact match for objects. * TypeDesc.OBJECT works fine for all objects. For primitive types, use * the appropriate TypeDesc. For an int, the type is TypeDesc.INT. * * @param type The type of data stored in the array. */ void storeToArray(TypeDesc type); // load-field-to-stack style instructions /** * Generates code that loads a value from a field from this class. * An object reference must be on the stack. After the generated code * has executed, the object reference is replaced by the value retrieved * from the field. */ void loadField(String fieldName, TypeDesc type); /** * Generates code that loads a value from a field from any class. * An object reference must be on the stack. After the generated code * has executed, the object reference is replaced by the value retrieved * from the field. */ void loadField(String className, String fieldName, TypeDesc type); /** * Generates code that loads a value from a field from any class. * An object reference must be on the stack. After the generated code * has executed, the object reference is replaced by the value retrieved * from the field. * * @throws IllegalArgumentException if classDesc refers to an array or * primitive type */ void loadField(TypeDesc classDesc, String fieldName, TypeDesc type); /** * Generates code that loads a value from a static field from this class. * After the generated code has executed, the value retrieved is placed * on the stack. */ void loadStaticField(String fieldName, TypeDesc type); /** * Generates code that loads a value from a static field from any class. * After the generated code has executed, the value retrieved is placed * on the stack. */ void loadStaticField(String className, String fieldName, TypeDesc type); /** * Generates code that loads a value from a static field from any class. * After the generated code has executed, the value retrieved is placed * on the stack. * * @throws IllegalArgumentException if classDesc refers to an array or * primitive type */ void loadStaticField(TypeDesc classDesc, String fieldName, TypeDesc type); // store-to-field-from-stack style instructions /** * Generates code that stores a value into a field from this class. * An object reference and value must be on the stack. After the generated * code has executed, the object reference and value are gone from * the stack. */ void storeField(String fieldName, TypeDesc type); /** * Generates code that stores a value into a field from any class. * An object reference and value must be on the stack. After the generated * code has executed, the object reference and value are gone from * the stack. */ void storeField(String className, String fieldName, TypeDesc type); /** * Generates code that stores a value into a field from any class. * An object reference and value must be on the stack. After the generated * code has executed, the object reference and value are gone from * the stack. * * @throws IllegalArgumentException if classDesc refers to an array or * primitive type */ void storeField(TypeDesc classDesc, String fieldName, TypeDesc type); /** * Generates code that stores a value into a field from this class. * A value must be on the stack. After the generated * code has executed, the value is gone from the stack. */ void storeStaticField(String fieldName, TypeDesc type); /** * Generates code that stores a value into a field from any class. * A value must be on the stack. After the generated * code has executed, the value is gone from the stack. */ void storeStaticField(String className, String fieldName, TypeDesc type); /** * Generates code that stores a value into a field from any class. * A value must be on the stack. After the generated * code has executed, the value is gone from the stack. * * @throws IllegalArgumentException if classDesc refers to an array or * primitive type */ void storeStaticField(TypeDesc classDesc, String fieldName, TypeDesc type); // return style instructions /** * Generates code that returns void. */ void returnVoid(); /** * Generates code that returns an object or primitive type. The value to * return must be on the stack. * <p> * The type doesn't need to be an exact match for objects. * TypeDesc.OBJECT works fine for all objects. For primitive types, use * the appropriate TypeDesc. For an int, the type is TypeDesc.INT. */ void returnValue(TypeDesc type); // numerical conversion style instructions /** * Generates code that converts the value of a primitive type already * on the stack. Conversions between all primitive types are supported as * well as boxing and unboxing conversions. Some example conversions: * * <pre> * int to char * byte to double * Double to double * Float to boolean * long to Long * Double to Short * </pre> * * In all, 240 conversions are supported. * * @throws IllegalArgumentException if conversion not supported */ void convert(TypeDesc fromType, TypeDesc toType); /** * Generates code that converts the value of a primitive type already * on the stack. Conversions between all primitive types are supported as * well as boxing and unboxing conversions. Some example conversions: * * <pre> * int to char * byte to double * Double to double * Float to boolean * long to Long * Double to Short * </pre> * * In all, 240 conversions are supported. * * @param fpConvertMode controls floating point conversion if converting * float <--> int or double <--> long * @throws IllegalArgumentException if conversion not supported */ void convert(TypeDesc fromType, TypeDesc toType, int fpConvertMode); // invocation style instructions /** * Generates code to invoke a method. If the method is static, the method's * argument(s) must be on the stack. If the method is non-static, then the * object reference must also be on the stack, prior to the arguments. */ void invoke(Method method); /** * Generates code to invoke a virtual method in this class. The object * reference and the method's argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. */ void invokeVirtual(String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a virtual method in any class. The object * reference and the method's argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. */ void invokeVirtual(String className, String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a virtual method in any class. The object * reference and the method's argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. * @throws IllegalArgumentException if classDesc refers to an array or * primitive type */ void invokeVirtual(TypeDesc classDesc, String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a static method in this class. The method's * argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. */ void invokeStatic(String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a static method in any class. The method's * argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. */ void invokeStatic(String className, String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a static method in any class. The method's * argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. * @throws IllegalArgumentException if classDesc refers to an array or * primitive type */ void invokeStatic(TypeDesc classDesc, String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke an interface method in any class. The object * reference and the method's argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. */ void invokeInterface(String className, String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke an interface method in any class. The object * reference and the method's argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. * @throws IllegalArgumentException if classDesc refers to an array or * primitive type */ void invokeInterface(TypeDesc classDesc, String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a private method in this class. * The object reference and the method's argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. */ void invokePrivate(String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a method in the super class. * The object reference and the method's argument(s) must be on the stack. */ void invokeSuper(Method method); /** * Generates code to invoke a method in the super class. * The object reference and the method's argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. */ void invokeSuper(String superClassName, String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a method in the super class. * The object reference and the method's argument(s) must be on the stack. * * @param ret May be null if method returns void. * @param params May be null if method takes no parameters. * @throws IllegalArgumentException if superClassDesc refers to an array or * primitive type */ void invokeSuper(TypeDesc superClassDesc, String methodName, TypeDesc ret, TypeDesc[] params); /** * Generates code to invoke a class constructor in any class. The object * reference and the constructor's argument(s) must be on the stack. */ void invoke(Constructor constructor); /** * Generates code to invoke a class constructor in this class. The object * reference and the constructor's argument(s) must be on the stack. * * @param params May be null if constructor takes no parameters. */ void invokeConstructor(TypeDesc[] params); /** * Generates code to invoke a class constructor in any class. The object * reference and the constructor's argument(s) must be on the stack. * * @param params May be null if constructor takes no parameters. */ void invokeConstructor(String className, TypeDesc[] params); /** * Generates code to invoke a class constructor in any class. The object * reference and the constructor's argument(s) must be on the stack. * * @param params May be null if constructor takes no parameters. * @throws IllegalArgumentException if classDesc refers to an array or * primitive type */ void invokeConstructor(TypeDesc classDesc, TypeDesc[] params); /** * Generates code to invoke a super class constructor. The object * reference and the constructor's argument(s) must be on the stack. * * @param params May be null if constructor takes no parameters. */ void invokeSuperConstructor(TypeDesc[] params); // creation style instructions /** * Generates code to create a new object. Unless the new object is an * array, it is invalid until a constructor method is invoked on it. * <p> * If the specified type is an array, this call is equivalent to * newObject(type, 1). The size of the dimension must be on the operand * stack. To create multi-dimensional arrays, call * newObject(type, dimensions). * * @see #invokeConstructor */ void newObject(TypeDesc type); /** * Generates code to create a new array. The type descriptor specifies * the type of array to create. The dimensions parameter specifies the * amount of dimensions that will initialized, which may not be larger than * the amount of dimensions specified in the type. * <p> * For each dimension, its size must be on the operand stack. If the * specified dimensions is 0 and the type is not an array, then this call * is equivalent to newObject(type). */ void newObject(TypeDesc type, int dimensions); // stack operation style instructions /** * Generates code for the dup instruction. */ void dup(); /** * Generates code for the dup_x1 instruction. */ void dupX1(); /** * Generates code for the dup_x2 instruction. */ void dupX2(); /** * Generates code for the dup2 instruction. */ void dup2(); /** * Generates code for the dup2_x1 instruction. */ void dup2X1(); /** * Generates code for the dup2_x2 instruction. */ void dup2X2(); /** * Generates code for the pop instruction. */ void pop(); /** * Generates code for the pop2 instruction. */ void pop2(); /** * Generates code for the swap instruction. */ void swap(); /** * Generates code for a swap2 instruction. */ void swap2(); // flow control instructions /** * Generates code that performs an unconditional branch to the specified * location. * * @param location The location to branch to */ void branch(Location location); /** * Generates code that performs a conditional branch based on the * value of an object on the stack. A branch is performed based on whether * the object reference on the stack is null or not. * * <p>The generated instruction consumes the value on the stack. * * @param location The location to branch to * @param choice If true, do branch when null, else branch when not null */ void ifNullBranch(Location location, boolean choice); /** * Generates code that performs a conditional branch based on the value of * two object references on the stack. A branch is performed based on * whether the two objects are exactly the same. * * <p>The generated instruction consumes the two values on the stack. * * @param location The location to branch to * @param choice If true, branch when equal, else branch when not equal */ void ifEqualBranch(Location location, boolean choice); /** * Generates code the performs a conditional branch based on a comparison * between an int value on the stack and zero. The int value on the * stack is on the left side of the comparison expression. * * <p>The generated instruction consumes the value on the stack. * * @param location The location to branch to * @param choice One of "==", "!=", "<", ">=", ">" or "<=" * @throws IllegalArgumentException When the choice is not valid */ void ifZeroComparisonBranch(Location location, String choice) throws IllegalArgumentException; /** * Generates code the performs a conditional branch based on a comparison * between two int values on the stack. The first int value on the stack * is on the left side of the comparison expression. * * <p>The generated instruction consumes the two values on the stack. * * @param location The location to branch to * @param choice One of "==", "!=", "<", ">=", ">" or "<=" * @throws IllegalArgumentException When the choice is not valid */ void ifComparisonBranch(Location location, String choice) throws IllegalArgumentException; /** * Generates code the performs a conditional branch based on a comparison * between two values of the given type on the stack. The first int value * on the stack is on the left side of the comparison expression. When * comparing objects, only an identity comparison is performed. * * <p>When comparing floating point values, treatment of NaN requires * special attention. Ordinarily, it is assumed that the branch location * represents the target of a comparison failure, and that the code to * handle the "true" condition immediately follows the comparison. If this * is not the case, append a 't' suffix to the choice to indicate that the * target location is reached for a "true" condition. This suffix is * ignored if the type is not a float or double. * * <p>The generated instruction(s) consumes the two values on the stack. * * @param location The location to branch to * @param choice One of "==", "!=", "<", ">=", ">", "<=", "==t", "!=t", * "<t", ">=t", ">t", or "<=t". Object types can only be compared for * equality. * @param type Type to expect on the stack * @throws IllegalArgumentException When the choice is not valid */ void ifComparisonBranch(Location location, String choice, TypeDesc type) throws IllegalArgumentException; /** * Generates code for a switch statement. The generated code is either a * lookupswitch or tableswitch. The choice of which switch type to generate * is made based on the amount of bytes to be generated. A tableswitch * is usually smaller, unless the cases are sparse. * * <p>The key value to switch on must already be on the stack when this * instruction executes. It is consumed by the instruction. * * @param cases The values to match on. The array length must be the same * as for locations. * @param locations The locations to branch to for each case. * The array length must be the same as for cases. * @param defaultLocation The location to branch to if the key on * the stack was not matched. */ void switchBranch(int[] cases, Location[] locations, Location defaultLocation); /** * Generates code that performs a subroutine branch to the specified * location. The instruction generated is either jsr or jsr_w. It is most * often used for implementing a finally block. * * @param location The location to branch to */ void jsr(Location location); /** * Generates code that returns from a subroutine invoked by jsr. * * @param local The local variable reference that contains the return * address. The local variable must be of an object type. */ void ret(LocalVariable local); // math instructions /** * Generates code for either a unary or binary math operation on one * or two values pushed on the stack. * <p> * Pass in an opcode from the the Opcode class. The only valid math * opcodes are: * * <pre> * IADD, ISUB, IMUL, IDIV, IREM, INEG, IAND, IOR, IXOR, ISHL, ISHR, IUSHR * LADD, LSUB, LMUL, LDIV, LREM, LNEG, LAND, LOR, LXOR, LSHL, LSHR, LUSHR * FADD, FSUB, FMUL, FDIV, FREM, FNEG * DADD, DSUB, DMUL, DDIV, DREM, DNEG * * LCMP * FCMPG, FCMPL * DCMPG, DCMPL * </pre> * * A not operation (~) is performed by doing a loadConstant with either * -1 or -1L followed by math(Opcode.IXOR) or math(Opcode.LXOR). * * @param opcode An opcode from the Opcode class. * @throws IllegalArgumentException When the opcode selected is not * a math operation. * @see Opcode */ void math(byte opcode); // miscellaneous instructions /** * Generates code for an arraylength instruction. The object to get the * length from must already be on the stack. */ void arrayLength(); /** * Generates code that throws an exception. The object to throw must * already be on the stack. */ void throwObject(); /** * Generates code that performs an object cast operation. The object * to check must already be on the stack. */ void checkCast(TypeDesc type); /** * Generates code that performs an instanceof operation. The object to * check must already be on the stack. */ void instanceOf(TypeDesc type); /** * Generates code that increments a local integer variable by a signed * constant amount. */ void integerIncrement(LocalVariable local, int amount); /** * Generates code to enter the monitor on an object loaded on the stack. */ void monitorEnter(); /** * Generates code to exit the monitor on an object loaded on the stack. */ void monitorExit(); /** * Generates an instruction that does nothing. (No-OPeration) */ void nop(); /** * Generates a breakpoint instruction for use in a debugging environment. */ void breakpoint(); }