00001 package de.fub.bytecode.generic;
00002
00003 import de.fub.bytecode.Constants;
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 public class InstructionFactory implements InstructionConstants {
00015 protected ClassGen cg;
00016 protected ConstantPoolGen cp;
00017
00018
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
00028
00029 public InstructionFactory(ConstantPoolGen cp) {
00030 this(null, cp);
00031 }
00032
00033
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
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
00120
00121
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
00138
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
00167
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
00208
00209 public static StackInstruction createDup(int size) {
00210 return (size == 2)? (StackInstruction)DUP2 :
00211 (StackInstruction)DUP;
00212 }
00213
00214
00215
00216 public static StackInstruction createDup_1(int size) {
00217 return (size == 2)? (StackInstruction)DUP2_X1 :
00218 (StackInstruction)DUP_X1;
00219 }
00220
00221
00222
00223 public static StackInstruction createDup_2(int size) {
00224 return (size == 2)? (StackInstruction)DUP2_X2 :
00225 (StackInstruction)DUP_X2;
00226 }
00227
00228
00229
00230
00231
00232
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
00257
00258
00259
00260
00261
00262
00263
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++)
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
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
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
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
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
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
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
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 }