/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 com.sun.org.apache.bcel.internal.generic;

import com.sun.org.apache.bcel.internal.Constants;

Instances of this class may be used, e.g., to generate typed versions of instructions. Its main purpose is to be used as the byte code generating backend of a compiler. You can subclass it to add your own create methods.
Author:M. Dahm
See Also:
/** * Instances of this class may be used, e.g., to generate typed * versions of instructions. Its main purpose is to be used as the * byte code generating backend of a compiler. You can subclass it to * add your own create methods. * * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> * @see Constants */
public class InstructionFactory implements InstructionConstants, java.io.Serializable { protected ClassGen cg; protected ConstantPoolGen cp; public InstructionFactory(ClassGen cg, ConstantPoolGen cp) { this.cg = cg; this.cp = cp; }
Initialize with ClassGen object
/** Initialize with ClassGen object */
public InstructionFactory(ClassGen cg) { this(cg, cg.getConstantPool()); }
Initialize just with ConstantPoolGen object
/** Initialize just with ConstantPoolGen object */
public InstructionFactory(ConstantPoolGen cp) { this(null, cp); }
Create an invoke instruction.
Params:
  • class_name – name of the called class
  • name – name of the called method
  • ret_type – return type of method
  • arg_types – argument types of method
  • kind – how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL
See Also:
/** Create an invoke instruction. * * @param class_name name of the called class * @param name name of the called method * @param ret_type return type of method * @param arg_types argument types of method * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, * or INVOKESPECIAL * @see Constants */
public InvokeInstruction createInvoke(String class_name, String name, Type ret_type, Type[] arg_types, short kind) { int index; int nargs = 0; String signature = Type.getMethodSignature(ret_type, arg_types); for(int i=0; i < arg_types.length; i++) // Count size of arguments nargs += arg_types[i].getSize(); if(kind == Constants.INVOKEINTERFACE) index = cp.addInterfaceMethodref(class_name, name, signature); else index = cp.addMethodref(class_name, name, signature); switch(kind) { case Constants.INVOKESPECIAL: return new INVOKESPECIAL(index); case Constants.INVOKEVIRTUAL: return new INVOKEVIRTUAL(index); case Constants.INVOKESTATIC: return new INVOKESTATIC(index); case Constants.INVOKEINTERFACE: return new INVOKEINTERFACE(index, nargs + 1); default: throw new RuntimeException("Oops: Unknown invoke kind:" + kind); } }
Create a call to the most popular System.out.println() method.
Params:
  • s – the string to print
/** Create a call to the most popular System.out.println() method. * * @param s the string to print */
public InstructionList createPrintln(String s) { InstructionList il = new InstructionList(); int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;"); int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V"); il.append(new GETSTATIC(out)); il.append(new PUSH(cp, s)); il.append(new INVOKEVIRTUAL(println)); return il; }
Uses PUSH to push a constant value onto the stack.
Params:
  • value – must be of type Number, Boolean, Character or String
/** Uses PUSH to push a constant value onto the stack. * @param value must be of type Number, Boolean, Character or String */
public Instruction createConstant(Object value) { PUSH push; if(value instanceof Number) push = new PUSH(cp, (Number)value); else if(value instanceof String) push = new PUSH(cp, (String)value); else if(value instanceof Boolean) push = new PUSH(cp, (Boolean)value); else if(value instanceof Character) push = new PUSH(cp, (Character)value); else throw new ClassGenException("Illegal type: " + value.getClass()); return push.getInstruction(); } private static class MethodObject { Type[] arg_types; Type result_type; String[] arg_names; String class_name; String name; int access; MethodObject(String c, String n, Type r, Type[] a, int acc) { class_name = c; name = n; result_type = r; arg_types = a; access = acc; } } private InvokeInstruction createInvoke(MethodObject m, short kind) { return createInvoke(m.class_name, m.name, m.result_type, m.arg_types, kind); } private static MethodObject[] append_mos = { new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.STRING }, Constants.ACC_PUBLIC), new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.OBJECT }, Constants.ACC_PUBLIC), null, null, // indices 2, 3 new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }, Constants.ACC_PUBLIC), new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.CHAR }, Constants.ACC_PUBLIC), new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.FLOAT }, Constants.ACC_PUBLIC), new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.DOUBLE }, Constants.ACC_PUBLIC), new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.INT }, Constants.ACC_PUBLIC), new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(byte) new Type[] { Type.INT }, Constants.ACC_PUBLIC), new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(short) new Type[] { Type.INT }, Constants.ACC_PUBLIC), new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.LONG }, Constants.ACC_PUBLIC) }; private static final boolean isString(Type type) { return ((type instanceof ObjectType) && ((ObjectType)type).getClassName().equals("java.lang.String")); } public Instruction createAppend(Type type) { byte t = type.getType(); if(isString(type)) return createInvoke(append_mos[0], Constants.INVOKEVIRTUAL); switch(t) { case Constants.T_BOOLEAN: case Constants.T_CHAR: case Constants.T_FLOAT: case Constants.T_DOUBLE: case Constants.T_BYTE: case Constants.T_SHORT: case Constants.T_INT: case Constants.T_LONG : return createInvoke(append_mos[t], Constants.INVOKEVIRTUAL); case Constants.T_ARRAY: case Constants.T_OBJECT: return createInvoke(append_mos[1], Constants.INVOKEVIRTUAL); default: throw new RuntimeException("Oops: No append for this type? " + type); } }
Create a field instruction.
Params:
  • class_name – name of the accessed class
  • name – name of the referenced field
  • type – type of field
  • kind – how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC
See Also:
/** Create a field instruction. * * @param class_name name of the accessed class * @param name name of the referenced field * @param type type of field * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC * @see Constants */
public FieldInstruction createFieldAccess(String class_name, String name, Type type, short kind) { int index; String signature = type.getSignature(); index = cp.addFieldref(class_name, name, signature); switch(kind) { case Constants.GETFIELD: return new GETFIELD(index); case Constants.PUTFIELD: return new PUTFIELD(index); case Constants.GETSTATIC: return new GETSTATIC(index); case Constants.PUTSTATIC: return new PUTSTATIC(index); default: throw new RuntimeException("Oops: Unknown getfield kind:" + kind); } }
Create reference to `this'
/** Create reference to `this' */
public static Instruction createThis() { return new ALOAD(0); }
Create typed return
/** Create typed return */
public static ReturnInstruction createReturn(Type type) { switch(type.getType()) { case Constants.T_ARRAY: case Constants.T_OBJECT: return ARETURN; case Constants.T_INT: case Constants.T_SHORT: case Constants.T_BOOLEAN: case Constants.T_CHAR: case Constants.T_BYTE: return IRETURN; case Constants.T_FLOAT: return FRETURN; case Constants.T_DOUBLE: return DRETURN; case Constants.T_LONG: return LRETURN; case Constants.T_VOID: return RETURN; default: throw new RuntimeException("Invalid type: " + type); } } private static final ArithmeticInstruction createBinaryIntOp(char first, String op) { switch(first) { case '-' : return ISUB; case '+' : return IADD; case '%' : return IREM; case '*' : return IMUL; case '/' : return IDIV; case '&' : return IAND; case '|' : return IOR; case '^' : return IXOR; case '<' : return ISHL; case '>' : return op.equals(">>>")? (ArithmeticInstruction)IUSHR : (ArithmeticInstruction)ISHR; default: throw new RuntimeException("Invalid operand " + op); } } private static final ArithmeticInstruction createBinaryLongOp(char first, String op) { switch(first) { case '-' : return LSUB; case '+' : return LADD; case '%' : return LREM; case '*' : return LMUL; case '/' : return LDIV; case '&' : return LAND; case '|' : return LOR; case '^' : return LXOR; case '<' : return LSHL; case '>' : return op.equals(">>>")? (ArithmeticInstruction)LUSHR : (ArithmeticInstruction)LSHR; default: throw new RuntimeException("Invalid operand " + op); } } private static final ArithmeticInstruction createBinaryFloatOp(char op) { switch(op) { case '-' : return FSUB; case '+' : return FADD; case '*' : return FMUL; case '/' : return FDIV; default: throw new RuntimeException("Invalid operand " + op); } } private static final ArithmeticInstruction createBinaryDoubleOp(char op) { switch(op) { case '-' : return DSUB; case '+' : return DADD; case '*' : return DMUL; case '/' : return DDIV; default: throw new RuntimeException("Invalid operand " + op); } }
Create binary operation for simple basic types, such as int and float.
Params:
  • op – operation, such as "+", "*", "<<", etc.
/** * Create binary operation for simple basic types, such as int and float. * * @param op operation, such as "+", "*", "<<", etc. */
public static ArithmeticInstruction createBinaryOperation(String op, Type type) { char first = op.toCharArray()[0]; switch(type.getType()) { case Constants.T_BYTE: case Constants.T_SHORT: case Constants.T_INT: case Constants.T_CHAR: return createBinaryIntOp(first, op); case Constants.T_LONG: return createBinaryLongOp(first, op); case Constants.T_FLOAT: return createBinaryFloatOp(first); case Constants.T_DOUBLE: return createBinaryDoubleOp(first); default: throw new RuntimeException("Invalid type " + type); } }
Params:
  • size – size of operand, either 1 (int, e.g.) or 2 (double)
/** * @param size size of operand, either 1 (int, e.g.) or 2 (double) */
public static StackInstruction createPop(int size) { return (size == 2)? (StackInstruction)POP2 : (StackInstruction)POP; }
Params:
  • size – size of operand, either 1 (int, e.g.) or 2 (double)
/** * @param size size of operand, either 1 (int, e.g.) or 2 (double) */
public static StackInstruction createDup(int size) { return (size == 2)? (StackInstruction)DUP2 : (StackInstruction)DUP; }
Params:
  • size – size of operand, either 1 (int, e.g.) or 2 (double)
/** * @param size size of operand, either 1 (int, e.g.) or 2 (double) */
public static StackInstruction createDup_2(int size) { return (size == 2)? (StackInstruction)DUP2_X2 : (StackInstruction)DUP_X2; }
Params:
  • size – size of operand, either 1 (int, e.g.) or 2 (double)
/** * @param size size of operand, either 1 (int, e.g.) or 2 (double) */
public static StackInstruction createDup_1(int size) { return (size == 2)? (StackInstruction)DUP2_X1 : (StackInstruction)DUP_X1; }
Params:
  • index – index of local variable
/** * @param index index of local variable */
public static LocalVariableInstruction createStore(Type type, int index) { switch(type.getType()) { case Constants.T_BOOLEAN: case Constants.T_CHAR: case Constants.T_BYTE: case Constants.T_SHORT: case Constants.T_INT: return new ISTORE(index); case Constants.T_FLOAT: return new FSTORE(index); case Constants.T_DOUBLE: return new DSTORE(index); case Constants.T_LONG: return new LSTORE(index); case Constants.T_ARRAY: case Constants.T_OBJECT: return new ASTORE(index); default: throw new RuntimeException("Invalid type " + type); } }
Params:
  • index – index of local variable
/** * @param index index of local variable */
public static LocalVariableInstruction createLoad(Type type, int index) { switch(type.getType()) { case Constants.T_BOOLEAN: case Constants.T_CHAR: case Constants.T_BYTE: case Constants.T_SHORT: case Constants.T_INT: return new ILOAD(index); case Constants.T_FLOAT: return new FLOAD(index); case Constants.T_DOUBLE: return new DLOAD(index); case Constants.T_LONG: return new LLOAD(index); case Constants.T_ARRAY: case Constants.T_OBJECT: return new ALOAD(index); default: throw new RuntimeException("Invalid type " + type); } }
Params:
  • type – type of elements of array, i.e., array.getElementType()
/** * @param type type of elements of array, i.e., array.getElementType() */
public static ArrayInstruction createArrayLoad(Type type) { switch(type.getType()) { case Constants.T_BOOLEAN: case Constants.T_BYTE: return BALOAD; case Constants.T_CHAR: return CALOAD; case Constants.T_SHORT: return SALOAD; case Constants.T_INT: return IALOAD; case Constants.T_FLOAT: return FALOAD; case Constants.T_DOUBLE: return DALOAD; case Constants.T_LONG: return LALOAD; case Constants.T_ARRAY: case Constants.T_OBJECT: return AALOAD; default: throw new RuntimeException("Invalid type " + type); } }
Params:
  • type – type of elements of array, i.e., array.getElementType()
/** * @param type type of elements of array, i.e., array.getElementType() */
public static ArrayInstruction createArrayStore(Type type) { switch(type.getType()) { case Constants.T_BOOLEAN: case Constants.T_BYTE: return BASTORE; case Constants.T_CHAR: return CASTORE; case Constants.T_SHORT: return SASTORE; case Constants.T_INT: return IASTORE; case Constants.T_FLOAT: return FASTORE; case Constants.T_DOUBLE: return DASTORE; case Constants.T_LONG: return LASTORE; case Constants.T_ARRAY: case Constants.T_OBJECT: return AASTORE; default: throw new RuntimeException("Invalid type " + type); } }
Create conversion operation for two stack operands, this may be an I2C, instruction, e.g., if the operands are basic types and CHECKCAST if they are reference types.
/** Create conversion operation for two stack operands, this may be an I2C, instruction, e.g., * if the operands are basic types and CHECKCAST if they are reference types. */
public Instruction createCast(Type src_type, Type dest_type) { if((src_type instanceof BasicType) && (dest_type instanceof BasicType)) { byte dest = dest_type.getType(); byte src = src_type.getType(); if(dest == Constants.T_LONG && (src == Constants.T_CHAR || src == Constants.T_BYTE || src == Constants.T_SHORT)) src = Constants.T_INT; String[] short_names = { "C", "F", "D", "B", "S", "I", "L" }; String name = "com.sun.org.apache.bcel.internal.generic." + short_names[src - Constants.T_CHAR] + "2" + short_names[dest - Constants.T_CHAR]; Instruction i = null; try { i = (Instruction)java.lang.Class.forName(name).newInstance(); } catch(Exception e) { throw new RuntimeException("Could not find instruction: " + name); } return i; } else if((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) { if(dest_type instanceof ArrayType) return new CHECKCAST(cp.addArrayClass((ArrayType)dest_type)); else return new CHECKCAST(cp.addClass(((ObjectType)dest_type).getClassName())); } else throw new RuntimeException("Can not cast " + src_type + " to " + dest_type); } public GETFIELD createGetField(String class_name, String name, Type t) { return new GETFIELD(cp.addFieldref(class_name, name, t.getSignature())); } public GETSTATIC createGetStatic(String class_name, String name, Type t) { return new GETSTATIC(cp.addFieldref(class_name, name, t.getSignature())); } public PUTFIELD createPutField(String class_name, String name, Type t) { return new PUTFIELD(cp.addFieldref(class_name, name, t.getSignature())); } public PUTSTATIC createPutStatic(String class_name, String name, Type t) { return new PUTSTATIC(cp.addFieldref(class_name, name, t.getSignature())); } public CHECKCAST createCheckCast(ReferenceType t) { if(t instanceof ArrayType) return new CHECKCAST(cp.addArrayClass((ArrayType)t)); else return new CHECKCAST(cp.addClass((ObjectType)t)); } public INSTANCEOF createInstanceOf(ReferenceType t) { if(t instanceof ArrayType) return new INSTANCEOF(cp.addArrayClass((ArrayType)t)); else return new INSTANCEOF(cp.addClass((ObjectType)t)); } public NEW createNew(ObjectType t) { return new NEW(cp.addClass(t)); } public NEW createNew(String s) { return createNew(new ObjectType(s)); }
Create new array of given size and type.
Returns:an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction
/** Create new array of given size and type. * @return an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction */
public Instruction createNewArray(Type t, short dim) { if(dim == 1) { if(t instanceof ObjectType) return new ANEWARRAY(cp.addClass((ObjectType)t)); else if(t instanceof ArrayType) return new ANEWARRAY(cp.addArrayClass((ArrayType)t)); else return new NEWARRAY(((BasicType)t).getType()); } else { ArrayType at; if(t instanceof ArrayType) at = (ArrayType)t; else at = new ArrayType(t, dim); return new MULTIANEWARRAY(cp.addArrayClass(at), dim); } }
Create "null" value for reference types, 0 for basic types like int
/** Create "null" value for reference types, 0 for basic types like int */
public static Instruction createNull(Type type) { switch(type.getType()) { case Constants.T_ARRAY: case Constants.T_OBJECT: return ACONST_NULL; case Constants.T_INT: case Constants.T_SHORT: case Constants.T_BOOLEAN: case Constants.T_CHAR: case Constants.T_BYTE: return ICONST_0; case Constants.T_FLOAT: return FCONST_0; case Constants.T_DOUBLE: return DCONST_0; case Constants.T_LONG: return LCONST_0; case Constants.T_VOID: return NOP; default: throw new RuntimeException("Invalid type: " + type); } }
Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH. For those you should use the SWITCH compound instruction.
/** Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH. * For those you should use the SWITCH compound instruction. */
public static BranchInstruction createBranchInstruction(short opcode, InstructionHandle target) { switch(opcode) { case Constants.IFEQ: return new IFEQ(target); case Constants.IFNE: return new IFNE(target); case Constants.IFLT: return new IFLT(target); case Constants.IFGE: return new IFGE(target); case Constants.IFGT: return new IFGT(target); case Constants.IFLE: return new IFLE(target); case Constants.IF_ICMPEQ: return new IF_ICMPEQ(target); case Constants.IF_ICMPNE: return new IF_ICMPNE(target); case Constants.IF_ICMPLT: return new IF_ICMPLT(target); case Constants.IF_ICMPGE: return new IF_ICMPGE(target); case Constants.IF_ICMPGT: return new IF_ICMPGT(target); case Constants.IF_ICMPLE: return new IF_ICMPLE(target); case Constants.IF_ACMPEQ: return new IF_ACMPEQ(target); case Constants.IF_ACMPNE: return new IF_ACMPNE(target); case Constants.GOTO: return new GOTO(target); case Constants.JSR: return new JSR(target); case Constants.IFNULL: return new IFNULL(target); case Constants.IFNONNULL: return new IFNONNULL(target); case Constants.GOTO_W: return new GOTO_W(target); case Constants.JSR_W: return new JSR_W(target); default: throw new RuntimeException("Invalid opcode: " + opcode); } } public void setClassGen(ClassGen c) { cg = c; } public ClassGen getClassGen() { return cg; } public void setConstantPool(ConstantPoolGen c) { cp = c; } public ConstantPoolGen getConstantPool() { return cp; } }