package org.aspectj.apache.bcel.generic;
import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.classfile.ConstantPool;
import org.aspectj.apache.bcel.classfile.Utility;
public class InstructionFactory implements InstructionConstants {
protected ClassGen cg;
protected ConstantPool cp;
public InstructionFactory(ClassGen cg, ConstantPool cp) {
this.cg = cg;
this.cp = cp;
}
public InstructionFactory(ClassGen cg) {
this(cg, cg.getConstantPool());
}
public InstructionFactory(ConstantPool cp) {
this(null, cp);
}
public InvokeInstruction createInvoke(String class_name, String name, Type ret_type, Type[] arg_types, short kind) {
return createInvoke(class_name, name, ret_type, arg_types, kind, false);
}
public InvokeInstruction createInvoke(String class_name, String name, Type ret_type, Type[] arg_types, short kind, boolean isInterface) {
String signature = Utility.toMethodSignature(ret_type, arg_types);
int index;
if (kind == Constants.INVOKEINTERFACE || isInterface) {
index = cp.addInterfaceMethodref(class_name, name, signature);
} else if (kind == Constants.INVOKEDYNAMIC){
throw new IllegalStateException("NYI");
} else {
index = cp.addMethodref(class_name, name, signature);
}
switch (kind) {
case Constants.INVOKESPECIAL:
return new InvokeInstruction(Constants.INVOKESPECIAL, index);
case Constants.INVOKEVIRTUAL:
return new InvokeInstruction(Constants.INVOKEVIRTUAL, index);
case Constants.INVOKESTATIC:
return new InvokeInstruction(Constants.INVOKESTATIC, index);
case Constants.INVOKEINTERFACE:
int nargs = 0;
for (int i = 0; i < arg_types.length; i++) {
nargs += arg_types[i].getSize();
}
return new INVOKEINTERFACE(index, nargs + 1, 0);
default:
throw new RuntimeException("Oops: Unknown invoke kind:" + kind);
}
}
public InvokeInstruction createInvoke(String class_name, String name, String signature, short kind) {
int index;
if (kind == Constants.INVOKEINTERFACE) {
index = cp.addInterfaceMethodref(class_name, name, signature);
} else if (kind == Constants.INVOKEDYNAMIC){
throw new IllegalStateException("NYI");
} else {
index = cp.addMethodref(class_name, name, signature);
}
switch (kind) {
case Constants.INVOKESPECIAL:
return new InvokeInstruction(Constants.INVOKESPECIAL, index);
case Constants.INVOKEVIRTUAL:
return new InvokeInstruction(Constants.INVOKEVIRTUAL, index);
case Constants.INVOKESTATIC:
return new InvokeInstruction(Constants.INVOKESTATIC, index);
case Constants.INVOKEINTERFACE:
Type[] argumentTypes = Type.getArgumentTypes(signature);
int nargs = 0;
for (int i = 0; i < argumentTypes.length; i++) {
nargs += argumentTypes[i].getSize();
}
return new INVOKEINTERFACE(index, nargs + 1, 0);
default:
throw new RuntimeException("Oops: Unknown invoke kind:" + kind);
}
}
public static Instruction createALOAD(int n) {
if (n < 4) {
return new InstructionLV((short) (Constants.ALOAD_0 + n));
}
return new InstructionLV(Constants.ALOAD, n);
}
public static Instruction createASTORE(int n) {
if (n < 4) {
return new InstructionLV((short) (Constants.ASTORE_0 + n));
}
return new InstructionLV(Constants.ASTORE, n);
}
public Instruction createConstant(Object value) {
Instruction instruction;
if (value instanceof Number) {
instruction = InstructionFactory.PUSH(cp, (Number) value);
} else if (value instanceof String) {
instruction = InstructionFactory.PUSH(cp, (String) value);
} else if (value instanceof Boolean) {
instruction = InstructionFactory.PUSH(cp, (Boolean) value);
} else if (value instanceof Character) {
instruction = InstructionFactory.PUSH(cp, (Character) value);
} else if (value instanceof ObjectType) {
instruction = InstructionFactory.PUSH(cp, (ObjectType) value);
} else {
throw new ClassGenException("Illegal type: " + value.getClass());
}
return instruction;
}
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 FieldInstruction(Constants.GETFIELD, index);
case Constants.PUTFIELD:
return new FieldInstruction(Constants.PUTFIELD, index);
case Constants.GETSTATIC:
return new FieldInstruction(Constants.GETSTATIC, index);
case Constants.PUTSTATIC:
return new FieldInstruction(Constants.PUTSTATIC, index);
default:
throw new RuntimeException("Oops: Unknown getfield kind:" + kind);
}
}
public static Instruction createThis() {
return new InstructionLV(Constants.ALOAD, 0);
}
public static Instruction 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);
}
}
public static Instruction createPop(int size) {
return (size == 2) ? POP2 : POP;
}
public static Instruction createDup(int size) {
return (size == 2) ? DUP2 : DUP;
}
public static Instruction createDup_2(int size) {
return (size == 2) ? DUP2_X2 : DUP_X2;
}
public static Instruction createDup_1(int size) {
return (size == 2) ? DUP2_X1 : DUP_X1;
}
public static InstructionLV 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 InstructionLV(Constants.ISTORE, index);
case Constants.T_FLOAT:
return new InstructionLV(Constants.FSTORE, index);
case Constants.T_DOUBLE:
return new InstructionLV(Constants.DSTORE, index);
case Constants.T_LONG:
return new InstructionLV(Constants.LSTORE, index);
case Constants.T_ARRAY:
case Constants.T_OBJECT:
return new InstructionLV(Constants.ASTORE, index);
default:
throw new RuntimeException("Invalid type " + type);
}
}
public static InstructionLV 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 InstructionLV(Constants.ILOAD, index);
case Constants.T_FLOAT:
return new InstructionLV(Constants.FLOAD, index);
case Constants.T_DOUBLE:
return new InstructionLV(Constants.DLOAD, index);
case Constants.T_LONG:
return new InstructionLV(Constants.LLOAD, index);
case Constants.T_ARRAY:
case Constants.T_OBJECT:
return new InstructionLV(Constants.ALOAD, index);
default:
throw new RuntimeException("Invalid type " + type);
}
}
public static Instruction 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);
}
}
public static Instruction 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);
}
}
private static final char[] shortNames = { 'C', 'F', 'D', 'B', 'S', 'I', 'L' };
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;
}
if (src == Constants.T_DOUBLE) {
switch (dest) {
case Constants.T_FLOAT:
return InstructionConstants.D2F;
case Constants.T_INT:
return InstructionConstants.D2I;
case Constants.T_LONG:
return InstructionConstants.D2L;
}
} else if (src == Constants.T_FLOAT) {
switch (dest) {
case Constants.T_DOUBLE:
return InstructionConstants.F2D;
case Constants.T_INT:
return InstructionConstants.F2I;
case Constants.T_LONG:
return InstructionConstants.F2L;
}
} else if (src == Constants.T_INT) {
switch (dest) {
case Constants.T_BYTE:
return InstructionConstants.I2B;
case Constants.T_CHAR:
return InstructionConstants.I2C;
case Constants.T_DOUBLE:
return InstructionConstants.I2D;
case Constants.T_FLOAT:
return InstructionConstants.I2F;
case Constants.T_LONG:
return InstructionConstants.I2L;
case Constants.T_SHORT:
return InstructionConstants.I2S;
}
} else if (src == Constants.T_LONG) {
switch (dest) {
case Constants.T_DOUBLE:
return InstructionConstants.L2D;
case Constants.T_FLOAT:
return InstructionConstants.L2F;
case Constants.T_INT:
return InstructionConstants.L2I;
}
}
return null;
} else if ((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) {
if (dest_type instanceof ArrayType) {
return new InstructionCP(Constants.CHECKCAST, cp.addArrayClass((ArrayType) dest_type));
} else {
return new InstructionCP(Constants.CHECKCAST, cp.addClass(((ObjectType) dest_type).getClassName()));
}
} else {
throw new RuntimeException("Can not cast " + src_type + " to " + dest_type);
}
}
public FieldInstruction createGetField(String class_name, String name, Type t) {
return new FieldInstruction(Constants.GETFIELD, cp.addFieldref(class_name, name, t.getSignature()));
}
public FieldInstruction createGetStatic(String class_name, String name, Type t) {
return new FieldInstruction(Constants.GETSTATIC, cp.addFieldref(class_name, name, t.getSignature()));
}
public FieldInstruction createPutField(String class_name, String name, Type t) {
return new FieldInstruction(Constants.PUTFIELD, cp.addFieldref(class_name, name, t.getSignature()));
}
public FieldInstruction createPutStatic(String class_name, String name, Type t) {
return new FieldInstruction(Constants.PUTSTATIC, cp.addFieldref(class_name, name, t.getSignature()));
}
public Instruction createCheckCast(ReferenceType t) {
if (t instanceof ArrayType) {
return new InstructionCP(Constants.CHECKCAST, cp.addArrayClass((ArrayType) t));
} else {
return new InstructionCP(Constants.CHECKCAST, cp.addClass((ObjectType) t));
}
}
public Instruction createInstanceOf(ReferenceType t) {
if (t instanceof ArrayType) {
return new InstructionCP(Constants.INSTANCEOF, cp.addArrayClass((ArrayType) t));
} else {
return new InstructionCP(Constants.INSTANCEOF, cp.addClass((ObjectType) t));
}
}
public Instruction createNew(ObjectType t) {
return new InstructionCP(Constants.NEW, cp.addClass(t));
}
public Instruction createNew(String s) {
return createNew(new ObjectType(s));
}
public Instruction createNewArray(Type t, short dim) {
if (dim == 1) {
if (t instanceof ObjectType) {
return new InstructionCP(Constants.ANEWARRAY, cp.addClass((ObjectType) t));
} else if (t instanceof ArrayType) {
return new InstructionCP(Constants.ANEWARRAY, cp.addArrayClass((ArrayType) t));
} else {
return new InstructionByte(Constants.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);
}
}
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);
}
}
public static InstructionBranch createBranchInstruction(short opcode, InstructionHandle target) {
switch (opcode) {
case Constants.IFEQ:
return new InstructionBranch(Constants.IFEQ, target);
case Constants.IFNE:
return new InstructionBranch(Constants.IFNE, target);
case Constants.IFLT:
return new InstructionBranch(Constants.IFLT, target);
case Constants.IFGE:
return new InstructionBranch(Constants.IFGE, target);
case Constants.IFGT:
return new InstructionBranch(Constants.IFGT, target);
case Constants.IFLE:
return new InstructionBranch(Constants.IFLE, target);
case Constants.IF_ICMPEQ:
return new InstructionBranch(Constants.IF_ICMPEQ, target);
case Constants.IF_ICMPNE:
return new InstructionBranch(Constants.IF_ICMPNE, target);
case Constants.IF_ICMPLT:
return new InstructionBranch(Constants.IF_ICMPLT, target);
case Constants.IF_ICMPGE:
return new InstructionBranch(Constants.IF_ICMPGE, target);
case Constants.IF_ICMPGT:
return new InstructionBranch(Constants.IF_ICMPGT, target);
case Constants.IF_ICMPLE:
return new InstructionBranch(Constants.IF_ICMPLE, target);
case Constants.IF_ACMPEQ:
return new InstructionBranch(Constants.IF_ACMPEQ, target);
case Constants.IF_ACMPNE:
return new InstructionBranch(Constants.IF_ACMPNE, target);
case Constants.GOTO:
return new InstructionBranch(Constants.GOTO, target);
case Constants.JSR:
return new InstructionBranch(Constants.JSR, target);
case Constants.IFNULL:
return new InstructionBranch(Constants.IFNULL, target);
case Constants.IFNONNULL:
return new InstructionBranch(Constants.IFNONNULL, target);
case Constants.GOTO_W:
return new InstructionBranch(Constants.GOTO_W, target);
case Constants.JSR_W:
return new InstructionBranch(Constants.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(ConstantPool c) {
cp = c;
}
public ConstantPool getConstantPool() {
return cp;
}
public static Instruction PUSH(ConstantPool cp, int value) {
Instruction instruction = null;
if ((value >= -1) && (value <= 5)) {
return INSTRUCTIONS[Constants.ICONST_0 + value];
} else if ((value >= -128) && (value <= 127)) {
instruction = new InstructionByte(Constants.BIPUSH, (byte) value);
} else if ((value >= -32768) && (value <= 32767)) {
instruction = new InstructionShort(Constants.SIPUSH, (short) value);
} else
{
int pos = cp.addInteger(value);
if (pos <= Constants.MAX_BYTE) {
instruction = new InstructionCP(Constants.LDC, pos);
} else {
instruction = new InstructionCP(Constants.LDC_W, pos);
}
}
return instruction;
}
public static Instruction PUSH(ConstantPool cp, ObjectType t) {
return new InstructionCP(Constants.LDC_W, cp.addClass(t));
}
public static Instruction PUSH(ConstantPool cp, boolean value) {
return INSTRUCTIONS[Constants.ICONST_0 + (value ? 1 : 0)];
}
public static Instruction PUSH(ConstantPool cp, float value) {
Instruction instruction = null;
if (value == 0.0) {
instruction = FCONST_0;
} else if (value == 1.0) {
instruction = FCONST_1;
} else if (value == 2.0) {
instruction = FCONST_2;
} else {
int i = cp.addFloat(value);
instruction = new InstructionCP(i <= Constants.MAX_BYTE ? Constants.LDC : Constants.LDC_W, i);
}
return instruction;
}
public static Instruction PUSH(ConstantPool cp, long value) {
Instruction instruction = null;
if (value == 0) {
instruction = LCONST_0;
} else if (value == 1) {
instruction = LCONST_1;
} else {
instruction = new InstructionCP(Constants.LDC2_W, cp.addLong(value));
}
return instruction;
}
public static Instruction PUSH(ConstantPool cp, double value) {
Instruction instruction = null;
if (value == 0.0) {
instruction = DCONST_0;
} else if (value == 1.0) {
instruction = DCONST_1;
} else {
instruction = new InstructionCP(Constants.LDC2_W, cp.addDouble(value));
}
return instruction;
}
public static Instruction PUSH(ConstantPool cp, String value) {
Instruction instruction = null;
if (value == null) {
instruction = ACONST_NULL;
} else {
int i = cp.addString(value);
instruction = new InstructionCP(i <= Constants.MAX_BYTE ? Constants.LDC : Constants.LDC_W, i);
}
return instruction;
}
public static Instruction PUSH(ConstantPool cp, Number value) {
Instruction instruction = null;
if ((value instanceof Integer) || (value instanceof Short) || (value instanceof Byte)) {
instruction = PUSH(cp, value.intValue());
} else if (value instanceof Double) {
instruction = PUSH(cp, value.doubleValue());
} else if (value instanceof Float) {
instruction = PUSH(cp, value.floatValue());
} else if (value instanceof Long) {
instruction = PUSH(cp, value.longValue());
} else {
throw new ClassGenException("What's this: " + value);
}
return instruction;
}
public static Instruction PUSH(ConstantPool cp, Character value) {
return PUSH(cp, value.charValue());
}
public static Instruction PUSH(ConstantPool cp, Boolean value) {
return PUSH(cp, value.booleanValue());
}
public InstructionList PUSHCLASS(ConstantPool cp, String className) {
InstructionList iList = new InstructionList();
int classIndex = cp.addClass(className);
if (cg != null && cg.getMajor() >= Constants.MAJOR_1_5) {
if (classIndex <= Constants.MAX_BYTE) {
iList.append(new InstructionCP(Instruction.LDC, classIndex));
} else {
iList.append(new InstructionCP(Instruction.LDC_W, classIndex));
}
} else {
className = className.replace('/', '.');
iList.append(InstructionFactory.PUSH(cp, className));
iList.append(this.createInvoke("java.lang.Class", "forName", ObjectType.CLASS, Type.STRINGARRAY1,
Constants.INVOKESTATIC));
}
return iList;
}
}