package org.aspectj.apache.bcel.generic; /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache BCEL" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache BCEL", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ 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; /** * Abstract super class for all Java byte codes. * * @version $Id: Instruction.java,v 1.10 2011/04/05 15:15:33 aclement Exp $ * @author M. Dahm */ 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]; } /** * Use with caution, since 'BranchInstruction's have a 'target' reference which is not copied correctly (only basic types are). * This also applies for 'Select' instructions with their multiple branch targets. * * @return (shallow) copy of an instruction */ // GET RID OF THIS - make it throw an exception and track the callers final public Instruction copy() { // if overridden correctly can just return 'this' here if (InstructionConstants.INSTRUCTIONS[opcode] != null) { // immutable instructions do not need copying return this; } else { Instruction i = null; try {// OPTIMIZE is clone the right thing to do here? it is horrible i = (Instruction) clone(); } catch (CloneNotSupportedException e) { System.err.println(e); } return i; } } /** * Read an instruction bytecode from an input stream and return the appropriate object. * * @param file file to read from * @return instruction object being read */ 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; } /** * @return Number of words consumed from stack by this instruction, or Constants.UNPREDICTABLE, if this can not be computed * statically */ public int consumeStack(ConstantPool cpg) { return Constants.CONSUME_STACK[opcode]; } /** * @return Number of words produced onto stack by this instruction, or Constants.UNPREDICTABLE, if this can not be computed * statically */ public int produceStack(ConstantPool cpg) { return Constants.stackEntriesProduced[opcode]; } public short getOpcode() { return opcode; } public int getLength() { // if it is zero, it should have been provided by an overriding implementation of getLength() int len = Constants.iLen[opcode]; assert len != 0; // if (len == 0) { // throw new IllegalStateException("Length not right for " + getName().toUpperCase()); // } return len; } /** Some instructions may be reused, so don't do anything by default */ 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; // IMPLEMENT EQUALS AND HASHCODE IN THE SUBTYPES! // Instruction i1 = this; // Instruction i2 = (Instruction) that; // if (i1.opcode == i2.opcode) { // if (i1.isConstantInstruction()) { // return i1.getValue().equals(i2.getValue()); // } else if (i1.isIndexedInstruction()) { // return i1.getIndex() == i2.getIndex(); // } else if (i1.opcode == Constants.NEWARRAY) { // return ((InstructionByte) i1).getTypecode() == ((InstructionByte) i2).getTypecode(); // } else { // return true; // } // } // // return false; } @Override public int hashCode() { if (this.getClass() != Instruction.class) { throw new RuntimeException("NO WAY " + this.getClass()); } return opcode * 37; // int result = 17 + opcode * 37; // if (isConstantInstruction()) { // result = 37 * getValue().hashCode() + result; // } else if (isIndexedInstruction()) { // result = 37 * getIndex() + result; // } else if (opcode == Constants.NEWARRAY) { // result = 37 * ((InstructionByte) this).getTypecode() + result; // } // return result; } public Type getType() { return getType(null); } public Type getType(ConstantPool cp) { // if (types[opcode]==null) throw new RuntimeException(getName()+" is not a typed instruction"); 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; // if ((instFlags[opcode] & CONSTANT_INST) == 0) { // throw new RuntimeException(getName() + " is not a constant instruction"); // } switch (opcode) { case ICONST_M1: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: return 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; } // remove these from here, leave them in the InstructionLV public boolean isASTORE() { return false; } public boolean isALOAD() { return false; } public boolean isStoreInstruction() { return (Constants.instFlags[opcode] & STORE_INST) != 0; } // public boolean containsTarget(InstructionHandle ih) { // throw new IllegalStateException("Dont ask!!"); // } 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; // if ((Constants.instFlags[opcode] & Constants.LOADCLASS_INST) == 0) { // throw new IllegalStateException("This opcode " + opcode + " does not have the property " // + Long.toHexString(Constants.LOADCLASS_INST)); // } 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 isGoto() { // return opcode == GOTO || opcode == GOTO_W; // } public boolean isLocalVariableInstruction() { return (Constants.instFlags[opcode] & LV_INST) != 0; } /** * Long output format: 'name of opcode' "[" 'opcode number' "]" "(" 'length of instruction' ")" */ public String toString(boolean verbose) { if (verbose) { StringBuilder sb = new StringBuilder(); 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); } }