org.aspectj.apache.bcel.generic.Instruction.java Source code

Java tutorial

Introduction

Here is the source code for org.aspectj.apache.bcel.generic.Instruction.java

Source

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
 * <http://www.apache.org/>.
 */

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 <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
 */
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 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;
    }

    // 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) {
            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);
    }
}