|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package com.sun.org.apache.bcel.internal.generic; |
|
|
|
import com.sun.org.apache.bcel.internal.Const; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class InstructionFactory { |
|
|
|
|
|
private static final String[] short_names = { |
|
"C", "F", "D", "B", "S", "I", "L" |
|
}; |
|
|
|
private ClassGen cg; |
|
private ConstantPoolGen cp; |
|
|
|
public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) { |
|
this.cg = cg; |
|
this.cp = cp; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public InstructionFactory(final ClassGen cg) { |
|
this(cg, cg.getConstantPool()); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public InstructionFactory(final ConstantPoolGen cp) { |
|
this(null, cp); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public InvokeInstruction createInvoke(final String class_name, final String name, final Type ret_type, |
|
final Type[] arg_types, final short kind) { |
|
int index; |
|
int nargs = 0; |
|
final String signature = Type.getMethodSignature(ret_type, arg_types); |
|
for (final Type arg_type : arg_types) { |
|
nargs += arg_type.getSize(); |
|
} |
|
if (kind == Const.INVOKEINTERFACE) { |
|
index = cp.addInterfaceMethodref(class_name, name, signature); |
|
} else { |
|
index = cp.addMethodref(class_name, name, signature); |
|
} |
|
switch (kind) { |
|
case Const.INVOKESPECIAL: |
|
return new INVOKESPECIAL(index); |
|
case Const.INVOKEVIRTUAL: |
|
return new INVOKEVIRTUAL(index); |
|
case Const.INVOKESTATIC: |
|
return new INVOKESTATIC(index); |
|
case Const.INVOKEINTERFACE: |
|
return new INVOKEINTERFACE(index, nargs + 1); |
|
case Const.INVOKEDYNAMIC: |
|
return new INVOKEDYNAMIC(index); |
|
default: |
|
throw new RuntimeException("Oops: Unknown invoke kind: " + kind); |
|
} |
|
} |
|
|
|
/** |
|
* Create an invokedynamic instruction. |
|
* |
|
* @param bootstrap_index index into the bootstrap_methods array |
|
* @param name name of the called method |
|
* @param ret_type return type of method |
|
* @param arg_types argument types of method |
|
* @see Constants |
|
*/ |
|
/* |
|
* createInvokeDynamic only needed if instrumention code wants to generate |
|
* a new invokedynamic instruction. I don't think we need. (markro) |
|
* |
|
public InvokeInstruction createInvokeDynamic( int bootstrap_index, String name, Type ret_type, |
|
Type[] arg_types) { |
|
int index; |
|
int nargs = 0; |
|
String signature = Type.getMethodSignature(ret_type, arg_types); |
|
for (int i = 0; i < arg_types.length; i++) { |
|
nargs += arg_types[i].getSize(); |
|
} |
|
// UNDONE - needs to be added to ConstantPoolGen |
|
//index = cp.addInvokeDynamic(bootstrap_index, name, signature); |
|
index = 0; |
|
return new INVOKEDYNAMIC(index); |
|
} |
|
*/ |
|
|
|
|
|
|
|
|
|
*/ |
|
public InstructionList createPrintln(final String s) { |
|
final InstructionList il = new InstructionList(); |
|
final int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;"); |
|
final 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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Instruction createConstant(final 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 { |
|
|
|
final Type[] arg_types; |
|
final Type result_type; |
|
final String class_name; |
|
final String name; |
|
|
|
MethodObject(final String c, final String n, final Type r, final Type[] a) { |
|
class_name = c; |
|
name = n; |
|
result_type = r; |
|
arg_types = a; |
|
} |
|
} |
|
|
|
private InvokeInstruction createInvoke(final MethodObject m, final short kind) { |
|
return createInvoke(m.class_name, m.name, m.result_type, m.arg_types, kind); |
|
} |
|
|
|
private static final MethodObject[] append_mos = { |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[]{ |
|
Type.STRING |
|
}), |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[]{ |
|
Type.OBJECT |
|
}), |
|
null, |
|
null, |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[]{ |
|
Type.BOOLEAN |
|
}), |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[]{ |
|
Type.CHAR |
|
}), |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[]{ |
|
Type.FLOAT |
|
}), |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[]{ |
|
Type.DOUBLE |
|
}), |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[]{ |
|
Type.INT |
|
}), |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, |
|
new Type[]{ |
|
Type.INT |
|
}), |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, |
|
new Type[]{ |
|
Type.INT |
|
}), |
|
new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[]{ |
|
Type.LONG |
|
}) |
|
}; |
|
|
|
private static boolean isString(final Type type) { |
|
return (type instanceof ObjectType) |
|
&& ((ObjectType) type).getClassName().equals("java.lang.String"); |
|
} |
|
|
|
public Instruction createAppend(final Type type) { |
|
final byte t = type.getType(); |
|
if (isString(type)) { |
|
return createInvoke(append_mos[0], Const.INVOKEVIRTUAL); |
|
} |
|
switch (t) { |
|
case Const.T_BOOLEAN: |
|
case Const.T_CHAR: |
|
case Const.T_FLOAT: |
|
case Const.T_DOUBLE: |
|
case Const.T_BYTE: |
|
case Const.T_SHORT: |
|
case Const.T_INT: |
|
case Const.T_LONG: |
|
return createInvoke(append_mos[t], Const.INVOKEVIRTUAL); |
|
case Const.T_ARRAY: |
|
case Const.T_OBJECT: |
|
return createInvoke(append_mos[1], Const.INVOKEVIRTUAL); |
|
default: |
|
throw new RuntimeException("Oops: No append for this type? " + type); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public FieldInstruction createFieldAccess(final String class_name, final String name, final Type type, final short kind) { |
|
int index; |
|
final String signature = type.getSignature(); |
|
index = cp.addFieldref(class_name, name, signature); |
|
switch (kind) { |
|
case Const.GETFIELD: |
|
return new GETFIELD(index); |
|
case Const.PUTFIELD: |
|
return new PUTFIELD(index); |
|
case Const.GETSTATIC: |
|
return new GETSTATIC(index); |
|
case Const.PUTSTATIC: |
|
return new PUTSTATIC(index); |
|
default: |
|
throw new RuntimeException("Oops: Unknown getfield kind:" + kind); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static Instruction createThis() { |
|
return new ALOAD(0); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static ReturnInstruction createReturn(final Type type) { |
|
switch (type.getType()) { |
|
case Const.T_ARRAY: |
|
case Const.T_OBJECT: |
|
return InstructionConst.ARETURN; |
|
case Const.T_INT: |
|
case Const.T_SHORT: |
|
case Const.T_BOOLEAN: |
|
case Const.T_CHAR: |
|
case Const.T_BYTE: |
|
return InstructionConst.IRETURN; |
|
case Const.T_FLOAT: |
|
return InstructionConst.FRETURN; |
|
case Const.T_DOUBLE: |
|
return InstructionConst.DRETURN; |
|
case Const.T_LONG: |
|
return InstructionConst.LRETURN; |
|
case Const.T_VOID: |
|
return InstructionConst.RETURN; |
|
default: |
|
throw new RuntimeException("Invalid type: " + type); |
|
} |
|
} |
|
|
|
private static ArithmeticInstruction createBinaryIntOp(final char first, final String op) { |
|
switch (first) { |
|
case '-': |
|
return InstructionConst.ISUB; |
|
case '+': |
|
return InstructionConst.IADD; |
|
case '%': |
|
return InstructionConst.IREM; |
|
case '*': |
|
return InstructionConst.IMUL; |
|
case '/': |
|
return InstructionConst.IDIV; |
|
case '&': |
|
return InstructionConst.IAND; |
|
case '|': |
|
return InstructionConst.IOR; |
|
case '^': |
|
return InstructionConst.IXOR; |
|
case '<': |
|
return InstructionConst.ISHL; |
|
case '>': |
|
return op.equals(">>>") ? InstructionConst.IUSHR : InstructionConst.ISHR; |
|
default: |
|
throw new RuntimeException("Invalid operand " + op); |
|
} |
|
} |
|
|
|
private static ArithmeticInstruction createBinaryLongOp(final char first, final String op) { |
|
switch (first) { |
|
case '-': |
|
return InstructionConst.LSUB; |
|
case '+': |
|
return InstructionConst.LADD; |
|
case '%': |
|
return InstructionConst.LREM; |
|
case '*': |
|
return InstructionConst.LMUL; |
|
case '/': |
|
return InstructionConst.LDIV; |
|
case '&': |
|
return InstructionConst.LAND; |
|
case '|': |
|
return InstructionConst.LOR; |
|
case '^': |
|
return InstructionConst.LXOR; |
|
case '<': |
|
return InstructionConst.LSHL; |
|
case '>': |
|
return op.equals(">>>") ? InstructionConst.LUSHR : InstructionConst.LSHR; |
|
default: |
|
throw new RuntimeException("Invalid operand " + op); |
|
} |
|
} |
|
|
|
private static ArithmeticInstruction createBinaryFloatOp(final char op) { |
|
switch (op) { |
|
case '-': |
|
return InstructionConst.FSUB; |
|
case '+': |
|
return InstructionConst.FADD; |
|
case '*': |
|
return InstructionConst.FMUL; |
|
case '/': |
|
return InstructionConst.FDIV; |
|
case '%': |
|
return InstructionConst.FREM; |
|
default: |
|
throw new RuntimeException("Invalid operand " + op); |
|
} |
|
} |
|
|
|
private static ArithmeticInstruction createBinaryDoubleOp(final char op) { |
|
switch (op) { |
|
case '-': |
|
return InstructionConst.DSUB; |
|
case '+': |
|
return InstructionConst.DADD; |
|
case '*': |
|
return InstructionConst.DMUL; |
|
case '/': |
|
return InstructionConst.DDIV; |
|
case '%': |
|
return InstructionConst.DREM; |
|
default: |
|
throw new RuntimeException("Invalid operand " + op); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static ArithmeticInstruction createBinaryOperation(final String op, final Type type) { |
|
final char first = op.charAt(0); |
|
switch (type.getType()) { |
|
case Const.T_BYTE: |
|
case Const.T_SHORT: |
|
case Const.T_INT: |
|
case Const.T_CHAR: |
|
return createBinaryIntOp(first, op); |
|
case Const.T_LONG: |
|
return createBinaryLongOp(first, op); |
|
case Const.T_FLOAT: |
|
return createBinaryFloatOp(first); |
|
case Const.T_DOUBLE: |
|
return createBinaryDoubleOp(first); |
|
default: |
|
throw new RuntimeException("Invalid type " + type); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static StackInstruction createPop(final int size) { |
|
return (size == 2) ? InstructionConst.POP2 : InstructionConst.POP; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static StackInstruction createDup(final int size) { |
|
return (size == 2) ? InstructionConst.DUP2 : InstructionConst.DUP; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static StackInstruction createDup_2(final int size) { |
|
return (size == 2) ? InstructionConst.DUP2_X2 : InstructionConst.DUP_X2; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static StackInstruction createDup_1(final int size) { |
|
return (size == 2) ? InstructionConst.DUP2_X1 : InstructionConst.DUP_X1; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static LocalVariableInstruction createStore(final Type type, final int index) { |
|
switch (type.getType()) { |
|
case Const.T_BOOLEAN: |
|
case Const.T_CHAR: |
|
case Const.T_BYTE: |
|
case Const.T_SHORT: |
|
case Const.T_INT: |
|
return new ISTORE(index); |
|
case Const.T_FLOAT: |
|
return new FSTORE(index); |
|
case Const.T_DOUBLE: |
|
return new DSTORE(index); |
|
case Const.T_LONG: |
|
return new LSTORE(index); |
|
case Const.T_ARRAY: |
|
case Const.T_OBJECT: |
|
return new ASTORE(index); |
|
default: |
|
throw new RuntimeException("Invalid type " + type); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static LocalVariableInstruction createLoad(final Type type, final int index) { |
|
switch (type.getType()) { |
|
case Const.T_BOOLEAN: |
|
case Const.T_CHAR: |
|
case Const.T_BYTE: |
|
case Const.T_SHORT: |
|
case Const.T_INT: |
|
return new ILOAD(index); |
|
case Const.T_FLOAT: |
|
return new FLOAD(index); |
|
case Const.T_DOUBLE: |
|
return new DLOAD(index); |
|
case Const.T_LONG: |
|
return new LLOAD(index); |
|
case Const.T_ARRAY: |
|
case Const.T_OBJECT: |
|
return new ALOAD(index); |
|
default: |
|
throw new RuntimeException("Invalid type " + type); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static ArrayInstruction createArrayLoad(final Type type) { |
|
switch (type.getType()) { |
|
case Const.T_BOOLEAN: |
|
case Const.T_BYTE: |
|
return InstructionConst.BALOAD; |
|
case Const.T_CHAR: |
|
return InstructionConst.CALOAD; |
|
case Const.T_SHORT: |
|
return InstructionConst.SALOAD; |
|
case Const.T_INT: |
|
return InstructionConst.IALOAD; |
|
case Const.T_FLOAT: |
|
return InstructionConst.FALOAD; |
|
case Const.T_DOUBLE: |
|
return InstructionConst.DALOAD; |
|
case Const.T_LONG: |
|
return InstructionConst.LALOAD; |
|
case Const.T_ARRAY: |
|
case Const.T_OBJECT: |
|
return InstructionConst.AALOAD; |
|
default: |
|
throw new RuntimeException("Invalid type " + type); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static ArrayInstruction createArrayStore(final Type type) { |
|
switch (type.getType()) { |
|
case Const.T_BOOLEAN: |
|
case Const.T_BYTE: |
|
return InstructionConst.BASTORE; |
|
case Const.T_CHAR: |
|
return InstructionConst.CASTORE; |
|
case Const.T_SHORT: |
|
return InstructionConst.SASTORE; |
|
case Const.T_INT: |
|
return InstructionConst.IASTORE; |
|
case Const.T_FLOAT: |
|
return InstructionConst.FASTORE; |
|
case Const.T_DOUBLE: |
|
return InstructionConst.DASTORE; |
|
case Const.T_LONG: |
|
return InstructionConst.LASTORE; |
|
case Const.T_ARRAY: |
|
case Const.T_OBJECT: |
|
return InstructionConst.AASTORE; |
|
default: |
|
throw new RuntimeException("Invalid type " + type); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Instruction createCast(final Type src_type, final Type dest_type) { |
|
if ((src_type instanceof BasicType) && (dest_type instanceof BasicType)) { |
|
final byte dest = dest_type.getType(); |
|
byte src = src_type.getType(); |
|
if (dest == Const.T_LONG |
|
&& (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) { |
|
src = Const.T_INT; |
|
} |
|
final String name = "com.sun.org.apache.bcel.internal.generic." + short_names[src - Const.T_CHAR] + "2" |
|
+ short_names[dest - Const.T_CHAR]; |
|
Instruction i = null; |
|
try { |
|
i = (Instruction) java.lang.Class.forName(name).getDeclaredConstructor().newInstance(); |
|
} catch (final Exception e) { |
|
throw new RuntimeException("Could not find instruction: " + name, e); |
|
} |
|
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)); |
|
} |
|
return new CHECKCAST(cp.addClass(((ObjectType) dest_type).getClassName())); |
|
} else { |
|
throw new RuntimeException("Can not cast " + src_type + " to " + dest_type); |
|
} |
|
} |
|
|
|
public GETFIELD createGetField(final String class_name, final String name, final Type t) { |
|
return new GETFIELD(cp.addFieldref(class_name, name, t.getSignature())); |
|
} |
|
|
|
public GETSTATIC createGetStatic(final String class_name, final String name, final Type t) { |
|
return new GETSTATIC(cp.addFieldref(class_name, name, t.getSignature())); |
|
} |
|
|
|
public PUTFIELD createPutField(final String class_name, final String name, final Type t) { |
|
return new PUTFIELD(cp.addFieldref(class_name, name, t.getSignature())); |
|
} |
|
|
|
public PUTSTATIC createPutStatic(final String class_name, final String name, final Type t) { |
|
return new PUTSTATIC(cp.addFieldref(class_name, name, t.getSignature())); |
|
} |
|
|
|
public CHECKCAST createCheckCast(final ReferenceType t) { |
|
if (t instanceof ArrayType) { |
|
return new CHECKCAST(cp.addArrayClass((ArrayType) t)); |
|
} |
|
return new CHECKCAST(cp.addClass((ObjectType) t)); |
|
} |
|
|
|
public INSTANCEOF createInstanceOf(final ReferenceType t) { |
|
if (t instanceof ArrayType) { |
|
return new INSTANCEOF(cp.addArrayClass((ArrayType) t)); |
|
} |
|
return new INSTANCEOF(cp.addClass((ObjectType) t)); |
|
} |
|
|
|
public NEW createNew(final ObjectType t) { |
|
return new NEW(cp.addClass(t)); |
|
} |
|
|
|
public NEW createNew(final String s) { |
|
return createNew(ObjectType.getInstance(s)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Instruction createNewArray(final Type t, final 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(t.getType()); |
|
} |
|
} |
|
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(final Type type) { |
|
switch (type.getType()) { |
|
case Const.T_ARRAY: |
|
case Const.T_OBJECT: |
|
return InstructionConst.ACONST_NULL; |
|
case Const.T_INT: |
|
case Const.T_SHORT: |
|
case Const.T_BOOLEAN: |
|
case Const.T_CHAR: |
|
case Const.T_BYTE: |
|
return InstructionConst.ICONST_0; |
|
case Const.T_FLOAT: |
|
return InstructionConst.FCONST_0; |
|
case Const.T_DOUBLE: |
|
return InstructionConst.DCONST_0; |
|
case Const.T_LONG: |
|
return InstructionConst.LCONST_0; |
|
case Const.T_VOID: |
|
return InstructionConst.NOP; |
|
default: |
|
throw new RuntimeException("Invalid type: " + type); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public static BranchInstruction createBranchInstruction(final short opcode, final InstructionHandle target) { |
|
switch (opcode) { |
|
case Const.IFEQ: |
|
return new IFEQ(target); |
|
case Const.IFNE: |
|
return new IFNE(target); |
|
case Const.IFLT: |
|
return new IFLT(target); |
|
case Const.IFGE: |
|
return new IFGE(target); |
|
case Const.IFGT: |
|
return new IFGT(target); |
|
case Const.IFLE: |
|
return new IFLE(target); |
|
case Const.IF_ICMPEQ: |
|
return new IF_ICMPEQ(target); |
|
case Const.IF_ICMPNE: |
|
return new IF_ICMPNE(target); |
|
case Const.IF_ICMPLT: |
|
return new IF_ICMPLT(target); |
|
case Const.IF_ICMPGE: |
|
return new IF_ICMPGE(target); |
|
case Const.IF_ICMPGT: |
|
return new IF_ICMPGT(target); |
|
case Const.IF_ICMPLE: |
|
return new IF_ICMPLE(target); |
|
case Const.IF_ACMPEQ: |
|
return new IF_ACMPEQ(target); |
|
case Const.IF_ACMPNE: |
|
return new IF_ACMPNE(target); |
|
case Const.GOTO: |
|
return new GOTO(target); |
|
case Const.JSR: |
|
return new JSR(target); |
|
case Const.IFNULL: |
|
return new IFNULL(target); |
|
case Const.IFNONNULL: |
|
return new IFNONNULL(target); |
|
case Const.GOTO_W: |
|
return new GOTO_W(target); |
|
case Const.JSR_W: |
|
return new JSR_W(target); |
|
default: |
|
throw new RuntimeException("Invalid opcode: " + opcode); |
|
} |
|
} |
|
|
|
public void setClassGen(final ClassGen c) { |
|
cg = c; |
|
} |
|
|
|
public ClassGen getClassGen() { |
|
return cg; |
|
} |
|
|
|
public void setConstantPool(final ConstantPoolGen c) { |
|
cp = c; |
|
} |
|
|
|
public ConstantPoolGen getConstantPool() { |
|
return cp; |
|
} |
|
} |