package org.aspectj.apache.bcel.generic;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.classfile.ConstantPool;
import org.aspectj.apache.bcel.util.ByteSequence;
public class Instruction implements Cloneable, Serializable, Constants {
public short opcode = -1;
public Instruction(short opcode) {
this.opcode = opcode;
}
public void dump(DataOutputStream out) throws IOException {
out.writeByte(opcode);
}
public String getName() {
return Constants.OPCODE_NAMES[opcode];
}
final public Instruction copy() {
if (InstructionConstants.INSTRUCTIONS[opcode] != null) {
return this;
} else {
Instruction i = null;
try {
i = (Instruction) clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return i;
}
}
public static final Instruction readInstruction(ByteSequence bytes) throws IOException {
boolean wide = false;
short opcode = (short) bytes.readUnsignedByte();
if (opcode == Constants.WIDE) {
wide = true;
opcode = (short) bytes.readUnsignedByte();
}
Instruction constantInstruction = InstructionConstants.INSTRUCTIONS[opcode];
if (constantInstruction != null) {
return constantInstruction;
}
Instruction obj = null;
try {
switch (opcode) {
case Constants.BIPUSH:
obj = new InstructionByte(Constants.BIPUSH, bytes.readByte());
break;
case Constants.SIPUSH:
obj = new InstructionShort(Constants.SIPUSH, bytes.readShort());
break;
case Constants.LDC:
obj = new InstructionCP(Constants.LDC, bytes.readUnsignedByte());
break;
case Constants.LDC_W:
case Constants.LDC2_W:
obj = new InstructionCP(opcode, bytes.readUnsignedShort());
break;
case Constants.ILOAD:
case Constants.LLOAD:
case Constants.FLOAD:
case Constants.DLOAD:
case Constants.ALOAD:
case Constants.ISTORE:
case Constants.LSTORE:
case Constants.FSTORE:
case Constants.DSTORE:
case Constants.ASTORE:
obj = new InstructionLV(opcode, wide ? bytes.readUnsignedShort() : bytes.readUnsignedByte());
break;
case Constants.IINC:
obj = new IINC(wide ? bytes.readUnsignedShort() : bytes.readUnsignedByte(), wide ? bytes.readShort()
: bytes.readByte(), wide);
break;
case Constants.IFNULL:
case Constants.IFNONNULL:
case Constants.IFEQ:
case Constants.IFNE:
case Constants.IFLT:
case Constants.IFGE:
case Constants.IFGT:
case Constants.IFLE:
case Constants.IF_ICMPEQ:
case Constants.IF_ICMPNE:
case Constants.IF_ICMPLT:
case Constants.IF_ICMPGE:
case Constants.IF_ICMPGT:
case Constants.IF_ICMPLE:
case Constants.IF_ACMPEQ:
case Constants.IF_ACMPNE:
case Constants.GOTO:
case Constants.JSR:
obj = new InstructionBranch(opcode, bytes.readShort());
break;
case Constants.GOTO_W:
case Constants.JSR_W:
obj = new InstructionBranch(opcode, bytes.readInt());
break;
case Constants.TABLESWITCH:
obj = new TABLESWITCH(bytes);
break;
case Constants.LOOKUPSWITCH:
obj = new LOOKUPSWITCH(bytes);
break;
case Constants.RET:
obj = new RET(wide ? bytes.readUnsignedShort() : bytes.readUnsignedByte(), wide);
break;
case Constants.NEW:
obj = new InstructionCP(Constants.NEW, bytes.readUnsignedShort());
break;
case Constants.GETSTATIC:
case Constants.PUTSTATIC:
case Constants.GETFIELD:
case Constants.PUTFIELD:
obj = new FieldInstruction(opcode, bytes.readUnsignedShort());
break;
case Constants.INVOKEVIRTUAL:
case Constants.INVOKESPECIAL:
case Constants.INVOKESTATIC:
obj = new InvokeInstruction(opcode, bytes.readUnsignedShort());
break;
case Constants.INVOKEINTERFACE:
obj = new INVOKEINTERFACE(bytes.readUnsignedShort(), bytes.readUnsignedByte(), bytes.readByte());
break;
case Constants.INVOKEDYNAMIC:
obj = new InvokeDynamic(bytes.readUnsignedShort(),bytes.readUnsignedShort());
break;
case Constants.NEWARRAY:
obj = new InstructionByte(Constants.NEWARRAY, bytes.readByte());
break;
case Constants.ANEWARRAY:
case Constants.CHECKCAST:
obj = new InstructionCP(opcode, bytes.readUnsignedShort());
break;
case Constants.INSTANCEOF:
obj = new InstructionCP(Constants.INSTANCEOF, bytes.readUnsignedShort());
break;
case Constants.MULTIANEWARRAY:
obj = new MULTIANEWARRAY(bytes.readUnsignedShort(), bytes.readByte());
break;
default:
throw new ClassGenException("Illegal opcode detected");
}
} catch (ClassGenException e) {
throw e;
} catch (Exception e) {
throw new ClassGenException(e.toString());
}
return obj;
}
public int consumeStack(ConstantPool cpg) {
return Constants.CONSUME_STACK[opcode];
}
public int produceStack(ConstantPool cpg) {
return Constants.stackEntriesProduced[opcode];
}
public short getOpcode() {
return opcode;
}
public int getLength() {
int len = Constants.iLen[opcode];
assert len != 0;
return len;
}
void dispose() {
}
@Override
public boolean equals(Object other) {
if (this.getClass() != Instruction.class) {
throw new RuntimeException("NO WAY " + this.getClass());
}
if (!(other instanceof Instruction)) {
return false;
}
return ((Instruction) other).opcode == opcode;
}
@Override
public int hashCode() {
if (this.getClass() != Instruction.class) {
throw new RuntimeException("NO WAY " + this.getClass());
}
return opcode * 37;
}
public Type getType() {
return getType(null);
}
public Type getType(ConstantPool cp) {
Type t = Constants.types[opcode];
if (t != null) {
return t;
}
throw new RuntimeException("Do not know type for instruction " + getName() + "(" + opcode + ")");
}
public Number getValue() {
assert (instFlags[opcode] & CONSTANT_INST) == 0;
switch (opcode) {
case ICONST_M1:
case ICONST_0:
case ICONST_1:
case ICONST_2:
case ICONST_3:
case ICONST_4:
case ICONST_5:
return new Integer(opcode - ICONST_0);
default:
throw new IllegalStateException("Not implemented yet for " + getName());
}
}
public int getIndex() {
return -1;
}
public void setIndex(int i) {
throw new IllegalStateException("Shouldnt be asking " + getName().toUpperCase());
}
public Object getValue(ConstantPool cpg) {
throw new IllegalStateException("Shouldnt be asking " + getName().toUpperCase());
}
public boolean isLoadInstruction() {
return (Constants.instFlags[opcode] & LOAD_INST) != 0;
}
public boolean isASTORE() {
return false;
}
public boolean isALOAD() {
return false;
}
public boolean isStoreInstruction() {
return (Constants.instFlags[opcode] & STORE_INST) != 0;
}
public boolean isJsrInstruction() {
return (Constants.instFlags[opcode] & JSR_INSTRUCTION) != 0;
}
public boolean isConstantInstruction() {
return (Constants.instFlags[opcode] & CONSTANT_INST) != 0;
}
public boolean isConstantPoolInstruction() {
return (Constants.instFlags[opcode] & CP_INST) != 0;
}
public boolean isStackProducer() {
return Constants.stackEntriesProduced[opcode] != 0;
}
public boolean isStackConsumer() {
return Constants.CONSUME_STACK[opcode] != 0;
}
public boolean isIndexedInstruction() {
return (Constants.instFlags[opcode] & INDEXED) != 0;
}
public boolean isArrayCreationInstruction() {
return opcode == NEWARRAY || opcode == ANEWARRAY || opcode == MULTIANEWARRAY;
}
public ObjectType getLoadClassType(ConstantPool cpg) {
assert (Constants.instFlags[opcode] & Constants.LOADCLASS_INST) == 0;
Type t = getType(cpg);
if (t instanceof ArrayType) {
t = ((ArrayType) t).getBasicType();
}
return t instanceof ObjectType ? (ObjectType) t : null;
}
public boolean isReturnInstruction() {
return (Constants.instFlags[opcode] & RET_INST) != 0;
}
public boolean isLocalVariableInstruction() {
return (Constants.instFlags[opcode] & LV_INST) != 0;
}
public String toString(boolean verbose) {
if (verbose) {
StringBuffer sb = new StringBuffer();
sb.append(getName()).append("[").append(opcode).append("](size").append(Constants.iLen[opcode]).append(")");
return sb.toString();
} else {
return getName();
}
}
@Override
public String toString() {
return toString(true);
}
}