Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

InstructionFactory.java

00001 package de.fub.bytecode.generic;
00002 
00003 import de.fub.bytecode.Constants;
00004 
00005 /** 
00006  * Instances of this class may be used, e.g., to generate typed
00007  * versions of instructions.  Its main purpose is to be used as the
00008  * byte code generating backend of a compiler. You can subclass it to
00009  * add your own create methods.
00010  *
00011  * @version $Id: InstructionFactory.java,v 1.1.1.1 2002/01/24 03:41:40 pserver Exp $
00012  * @author <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00013  */
00014 public class InstructionFactory implements InstructionConstants {
00015   protected ClassGen        cg;
00016   protected ConstantPoolGen cp;
00017 
00018   /** Initialize with ClassGen object
00019    */
00020   public InstructionFactory(ClassGen cg) {
00021     this(cg, cg.getConstantPool());
00022   }  
00023   public InstructionFactory(ClassGen cg, ConstantPoolGen cp) {
00024     this.cg = cg;
00025     this.cp = cp;
00026   }  
00027   /** Initialize just with ConstantPoolGen object
00028    */
00029   public InstructionFactory(ConstantPoolGen cp) {
00030     this(null, cp);
00031   }  
00032   /**
00033    * @param type type of elements of array, i.e., array.getElementType()
00034    */
00035   public static ArrayInstruction createArrayLoad(Type type) {
00036     switch(type.getType()) {
00037     case Constants.T_BOOLEAN:
00038     case Constants.T_BYTE:   return BALOAD;
00039     case Constants.T_CHAR:   return CALOAD;
00040     case Constants.T_SHORT:  return SALOAD;
00041     case Constants.T_INT:    return IALOAD;
00042     case Constants.T_FLOAT:  return FALOAD;
00043     case Constants.T_DOUBLE: return DALOAD;
00044     case Constants.T_LONG:   return LALOAD;
00045     case Constants.T_ARRAY:
00046     case Constants.T_OBJECT: return AALOAD;
00047     default:       throw new RuntimeException("Invalid type " + type);
00048     }
00049   }  
00050   /**
00051    * @param type type of elements of array, i.e., array.getElementType()
00052    */
00053   public static ArrayInstruction createArrayStore(Type type) {
00054     switch(type.getType()) {
00055     case Constants.T_BOOLEAN:
00056     case Constants.T_BYTE:   return BASTORE;
00057     case Constants.T_CHAR:   return CASTORE;
00058     case Constants.T_SHORT:  return SASTORE;
00059     case Constants.T_INT:    return IASTORE;
00060     case Constants.T_FLOAT:  return FASTORE;
00061     case Constants.T_DOUBLE: return DASTORE;
00062     case Constants.T_LONG:   return LASTORE;
00063     case Constants.T_ARRAY:
00064     case Constants.T_OBJECT: return AASTORE;
00065     default:       throw new RuntimeException("Invalid type " + type);
00066     }
00067   }  
00068   private static final ArithmeticInstruction createBinaryDoubleOp(char op) {
00069     switch(op) {
00070     case '-' : return DSUB;
00071     case '+' : return DADD;
00072     case '*' : return DMUL;
00073     case '/' : return DDIV;
00074     default: throw new RuntimeException("Invalid operand " + op);
00075     }
00076   }  
00077   private static final ArithmeticInstruction createBinaryFloatOp(char op) {
00078     switch(op) {
00079     case '-' : return FSUB;
00080     case '+' : return FADD;
00081     case '*' : return FMUL;
00082     case '/' : return FDIV;
00083     default: throw new RuntimeException("Invalid operand " + op);
00084     }
00085   }  
00086   private static final ArithmeticInstruction createBinaryIntOp(char first, String op) {
00087     switch(first) {
00088     case '-' : return ISUB;
00089     case '+' : return IADD;
00090     case '%' : return IREM;
00091     case '*' : return IMUL;
00092     case '/' : return IDIV;
00093     case '&' : return IAND;
00094     case '|' : return IOR;
00095     case '^' : return IXOR;
00096     case '<' : return ISHL;
00097     case '>' : return op.equals(">>>")? (ArithmeticInstruction)IUSHR :
00098       (ArithmeticInstruction)ISHR;
00099     default: throw new RuntimeException("Invalid operand " + op);
00100     }
00101   }  
00102   private static final ArithmeticInstruction createBinaryLongOp(char first, String op) {
00103     switch(first) {
00104     case '-' : return LSUB;
00105     case '+' : return LADD;
00106     case '%' : return LREM;
00107     case '*' : return LMUL;
00108     case '/' : return LDIV;
00109     case '&' : return LAND;
00110     case '|' : return LOR;
00111     case '^' : return LXOR;
00112     case '<' : return LSHL;
00113     case '>' : return op.equals(">>>")? (ArithmeticInstruction)LUSHR :
00114       (ArithmeticInstruction)LSHR;
00115     default: throw new RuntimeException("Invalid operand " + op);
00116     }
00117   }  
00118   /**
00119    * Create binary operation for simple basic types, such as int and float.
00120    *
00121    * @param op operation, such as "+", "*", "<<", etc.
00122    */
00123   public static ArithmeticInstruction createBinaryOperation(String op, Type type) {
00124     char first = op.toCharArray()[0];
00125 
00126     switch(type.getType()) {
00127     case Constants.T_BYTE:
00128     case Constants.T_SHORT:
00129     case Constants.T_INT:
00130     case Constants.T_CHAR:    return createBinaryIntOp(first, op);
00131     case Constants.T_LONG:    return createBinaryLongOp(first, op);
00132     case Constants.T_FLOAT:   return createBinaryFloatOp(first);
00133     case Constants.T_DOUBLE:  return createBinaryDoubleOp(first);
00134     default:        throw new RuntimeException("Invalid type " + type);
00135     }
00136   }  
00137   /** Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH.
00138    * For those you should use the SWITCH compeund instruction.
00139    */
00140   public static BranchInstruction createBranchInstruction(short opcode, InstructionHandle target) {
00141     switch(opcode) {
00142     case Constants.IFEQ:      return new IFEQ(target);
00143     case Constants.IFNE:      return new IFNE(target);
00144     case Constants.IFLT:      return new IFLT(target);
00145     case Constants.IFGE:      return new IFGE(target);
00146     case Constants.IFGT:      return new IFGT(target);
00147     case Constants.IFLE:      return new IFLE(target);
00148     case Constants.IF_ICMPEQ: return new IF_ICMPEQ(target);
00149     case Constants.IF_ICMPNE: return new IF_ICMPNE(target);
00150     case Constants.IF_ICMPLT: return new IF_ICMPLT(target);
00151     case Constants.IF_ICMPGE: return new IF_ICMPGE(target);
00152     case Constants.IF_ICMPGT: return new IF_ICMPGT(target);
00153     case Constants.IF_ICMPLE: return new IF_ICMPLE(target);
00154     case Constants.IF_ACMPEQ: return new IF_ACMPEQ(target);
00155     case Constants.IF_ACMPNE: return new IF_ACMPNE(target);
00156     case Constants.GOTO:      return new GOTO(target);
00157     case Constants.JSR:       return new JSR(target);
00158     case Constants.IFNULL:    return new IFNULL(target);
00159     case Constants.IFNONNULL: return new IFNONNULL(target);
00160     case Constants.GOTO_W:    return new GOTO_W(target);
00161     case Constants.JSR_W:     return new JSR_W(target);
00162     default:
00163     throw new RuntimeException("Invalid opcode: " + opcode);
00164     }
00165   }  
00166   /** Create conversion operation for two stack operands, this may be an I2C, instruction, e.g.,
00167    * if the operands are basic types and CHECKCAST if they are reference types.
00168    */
00169   public Instruction createCast(Type src_type, Type dest_type) {
00170     if((src_type instanceof BasicType) && (dest_type instanceof BasicType)) {
00171       byte dest = dest_type.getType();
00172       byte src  = src_type.getType();
00173 
00174       if(dest == Constants.T_LONG && (src == Constants.T_CHAR || src == Constants.T_BYTE ||
00175                       src == Constants.T_SHORT))
00176     src = Constants.T_INT;
00177 
00178       String[] short_names = { "C", "F", "D", "B", "S", "I", "L" };
00179 
00180       String name = "de.fub.bytecode.generic." + short_names[src - Constants.T_CHAR] +
00181     "2" + short_names[dest - Constants.T_CHAR];
00182       
00183       Instruction i = null;
00184       try {
00185     i = (Instruction)java.lang.Class.forName(name).newInstance();
00186       } catch(Exception e) {
00187     throw new RuntimeException("Could not find instruction: " + name);
00188       }
00189 
00190       return i;
00191     } else if((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) {
00192       if(dest_type instanceof ArrayType)
00193     return new CHECKCAST(cp.addArrayClass((ArrayType)dest_type));
00194       else
00195     return new CHECKCAST(cp.addClass(((ObjectType)dest_type).getClassName()));
00196     }
00197     else
00198       throw new RuntimeException("Can not cast " + src_type + " to " + dest_type);
00199   }  
00200   public CHECKCAST createCheckCast(ReferenceType t) {
00201     if(t instanceof ArrayType)
00202       return new CHECKCAST(cp.addArrayClass((ArrayType)t));
00203     else
00204       return new CHECKCAST(cp.addClass((ObjectType)t));
00205   }  
00206   /**
00207    * @param size size of operand, either 1 (int, e.g.) or 2 (double)
00208    */
00209   public static StackInstruction createDup(int size) {
00210     return (size == 2)? (StackInstruction)DUP2 :
00211       (StackInstruction)DUP;
00212   }  
00213   /**
00214    * @param size size of operand, either 1 (int, e.g.) or 2 (double)
00215    */
00216   public static StackInstruction createDup_1(int size) {
00217     return (size == 2)? (StackInstruction)DUP2_X1 :
00218       (StackInstruction)DUP_X1;
00219   }  
00220   /**
00221    * @param size size of operand, either 1 (int, e.g.) or 2 (double)
00222    */
00223   public static StackInstruction createDup_2(int size) {
00224     return (size == 2)? (StackInstruction)DUP2_X2 :
00225       (StackInstruction)DUP_X2;
00226   }  
00227   /** Create a field instruction.
00228    *
00229    * @param class_name name of the accessed class
00230    * @param name name of the referenced field
00231    * @param type  type of field
00232    * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC
00233    */
00234   public FieldInstruction createFieldAccess(String class_name, String name, Type type, short kind) {
00235     int    index;
00236     String signature  = type.getSignature();
00237 
00238     index = cp.addFieldref(class_name, name, signature);
00239 
00240     switch(kind) {
00241     case Constants.GETFIELD:  return new GETFIELD(index);
00242     case Constants.PUTFIELD:  return new PUTFIELD(index);
00243     case Constants.GETSTATIC: return new GETSTATIC(index);
00244     case Constants.PUTSTATIC: return new PUTSTATIC(index);
00245 
00246     default:
00247       throw new RuntimeException("Oops: Unknown invoke kind:" + kind);
00248     }
00249   }  
00250   public GETFIELD createGetField(String class_name, String name, Type t) {
00251     return new GETFIELD(cp.addFieldref(class_name, name, t.getSignature()));
00252   }  
00253   public GETSTATIC createGetStatic(String class_name, String name, Type t) {
00254     return new GETSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
00255   }  
00256   /** Create an invoke instruction.
00257    *
00258    * @param class_name name of the called class
00259    * @param name name of the called method
00260    * @param ret_type return type of method
00261    * @param arg_types argument types of method
00262    * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL,
00263    * or INVOKESPECIAL
00264    */
00265   public InvokeInstruction createInvoke(String class_name, String name, Type ret_type,
00266                     Type[] arg_types, short kind) {
00267     int    index;
00268     int    nargs      = 0;
00269     String signature  = Type.getMethodSignature(ret_type, arg_types);
00270 
00271     for(int i=0; i < arg_types.length; i++) // Count size of arguments
00272       nargs += arg_types[i].getSize();
00273 
00274     if(kind == Constants.INVOKEINTERFACE)
00275       index = cp.addInterfaceMethodref(class_name, name, signature);
00276     else
00277       index = cp.addMethodref(class_name, name, signature);
00278 
00279     switch(kind) {
00280     case Constants.INVOKESPECIAL:   return new INVOKESPECIAL(index);
00281     case Constants.INVOKEVIRTUAL:   return new INVOKEVIRTUAL(index);
00282     case Constants.INVOKESTATIC:    return new INVOKESTATIC(index);
00283     case Constants.INVOKEINTERFACE: return new INVOKEINTERFACE(index, nargs + 1);
00284     default:
00285       throw new RuntimeException("Oops: Unknown invoke kind:" + kind);
00286     }
00287   }  
00288   /**
00289    * @param index index of local variable
00290    */
00291   public static LocalVariableInstruction createLoad(Type type, int index) {
00292     switch(type.getType()) {
00293     case Constants.T_BOOLEAN:
00294     case Constants.T_CHAR:
00295     case Constants.T_BYTE:
00296     case Constants.T_SHORT:
00297     case Constants.T_INT:    return new ILOAD(index);
00298     case Constants.T_FLOAT:  return new FLOAD(index);
00299     case Constants.T_DOUBLE: return new DLOAD(index);
00300     case Constants.T_LONG:   return new LLOAD(index);
00301     case Constants.T_ARRAY:
00302     case Constants.T_OBJECT: return new ALOAD(index);
00303     default:       throw new RuntimeException("Invalid type " + type);
00304     }
00305   }  
00306   public NEW createNew(ObjectType t) {
00307     return new NEW(cp.addClass(t));
00308   }  
00309   public NEW createNew(String s) {
00310     return createNew(new ObjectType(s));
00311   }  
00312   /** Create new array of given size and type.
00313    */
00314   public AllocationInstruction createNewArray(Type t, short dim) {
00315     if(dim == 1) {
00316       if(t instanceof ObjectType)
00317     return new ANEWARRAY(cp.addClass((ObjectType)t));
00318       else if(t instanceof ArrayType)
00319     return new ANEWARRAY(cp.addArrayClass((ArrayType)t));
00320       else
00321     return new NEWARRAY(((BasicType)t).getType());
00322     } else {
00323       ArrayType at;
00324 
00325       if(t instanceof ArrayType)
00326     at = (ArrayType)t;
00327       else
00328     at = new ArrayType(t, dim);
00329 
00330       return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
00331     }
00332   }  
00333   /** Create "null" value for reference types, 0 for basic types like int
00334    */
00335   public static Instruction createNull(Type type) {
00336     switch(type.getType()) {
00337     case Constants.T_ARRAY:
00338     case Constants.T_OBJECT:  return ACONST_NULL;
00339     case Constants.T_INT:
00340     case Constants.T_SHORT:
00341     case Constants.T_BOOLEAN:
00342     case Constants.T_CHAR: 
00343     case Constants.T_BYTE:    return ICONST_0;
00344     case Constants.T_FLOAT:   return FCONST_0;
00345     case Constants.T_DOUBLE:  return DCONST_0;
00346     case Constants.T_LONG:    return LCONST_0;
00347     case Constants.T_VOID:    return NOP;
00348 
00349     default:
00350       throw new RuntimeException("Invalid type: " + type);
00351     }
00352   }  
00353   /**
00354    * @param size size of operand, either 1 (int, e.g.) or 2 (double)
00355    */
00356   public static StackInstruction createPop(int size) {
00357     return (size == 2)? (StackInstruction)POP2 :
00358       (StackInstruction)POP;
00359   }  
00360   public PUTFIELD createPutField(String class_name, String name, Type t) {
00361     return new PUTFIELD(cp.addFieldref(class_name, name, t.getSignature()));
00362   }  
00363   public PUTSTATIC createPutStatic(String class_name, String name, Type t) {
00364     return new PUTSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
00365   }  
00366   /** Create typed return
00367    */
00368   public static ReturnInstruction createReturn(Type type) {
00369     switch(type.getType()) {
00370     case Constants.T_ARRAY:
00371     case Constants.T_OBJECT:  return ARETURN;
00372     case Constants.T_INT:
00373     case Constants.T_SHORT:
00374     case Constants.T_BOOLEAN:
00375     case Constants.T_CHAR: 
00376     case Constants.T_BYTE:    return IRETURN;
00377     case Constants.T_FLOAT:   return FRETURN;
00378     case Constants.T_DOUBLE:  return DRETURN;
00379     case Constants.T_LONG:    return LRETURN;
00380     case Constants.T_VOID:    return RETURN;
00381 
00382     default:
00383       throw new RuntimeException("Invalid type: " + type);
00384     }
00385   }  
00386   /**
00387    * @param index index of local variable
00388    */
00389   public static LocalVariableInstruction createStore(Type type, int index) {
00390     switch(type.getType()) {
00391     case Constants.T_BOOLEAN:
00392     case Constants.T_CHAR:
00393     case Constants.T_BYTE:
00394     case Constants.T_SHORT:
00395     case Constants.T_INT:    return new ISTORE(index);
00396     case Constants.T_FLOAT:  return new FSTORE(index);
00397     case Constants.T_DOUBLE: return new DSTORE(index);
00398     case Constants.T_LONG:   return new LSTORE(index);
00399     case Constants.T_ARRAY:
00400     case Constants.T_OBJECT: return new ASTORE(index);
00401     default:       throw new RuntimeException("Invalid type " + type);
00402     }
00403   }  
00404   /** Create reference to `this'
00405    */
00406   public static Instruction createThis() {
00407     return new ALOAD(0);
00408   }  
00409   public ClassGen        getClassGen()                  { return cg; }  
00410   public ConstantPoolGen getConstantPool()                  { return cp; }  
00411   public void            setClassGen(ClassGen c)        { cg = c; }  
00412   public void            setConstantPool(ConstantPoolGen c) { cp = c; }  
00413 }

Generated at Thu Feb 7 06:47:40 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001