286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/Apackage com.sun.org.apache.bcel.internal.generic;
286N/A
286N/A/* ====================================================================
286N/A * The Apache Software License, Version 1.1
286N/A *
286N/A * Copyright (c) 2001 The Apache Software Foundation. All rights
286N/A * reserved.
286N/A *
286N/A * Redistribution and use in source and binary forms, with or without
286N/A * modification, are permitted provided that the following conditions
286N/A * are met:
286N/A *
286N/A * 1. Redistributions of source code must retain the above copyright
286N/A * notice, this list of conditions and the following disclaimer.
286N/A *
286N/A * 2. Redistributions in binary form must reproduce the above copyright
286N/A * notice, this list of conditions and the following disclaimer in
286N/A * the documentation and/or other materials provided with the
286N/A * distribution.
286N/A *
286N/A * 3. The end-user documentation included with the redistribution,
286N/A * if any, must include the following acknowledgment:
286N/A * "This product includes software developed by the
286N/A * Apache Software Foundation (http://www.apache.org/)."
286N/A * Alternately, this acknowledgment may appear in the software itself,
286N/A * if and wherever such third-party acknowledgments normally appear.
286N/A *
286N/A * 4. The names "Apache" and "Apache Software Foundation" and
286N/A * "Apache BCEL" must not be used to endorse or promote products
286N/A * derived from this software without prior written permission. For
286N/A * written permission, please contact apache@apache.org.
286N/A *
286N/A * 5. Products derived from this software may not be called "Apache",
286N/A * "Apache BCEL", nor may "Apache" appear in their name, without
286N/A * prior written permission of the Apache Software Foundation.
286N/A *
286N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
286N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
286N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
286N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
286N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
286N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
286N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
286N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
286N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
286N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
286N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
286N/A * SUCH DAMAGE.
286N/A * ====================================================================
286N/A *
286N/A * This software consists of voluntary contributions made by many
286N/A * individuals on behalf of the Apache Software Foundation. For more
286N/A * information on the Apache Software Foundation, please see
286N/A * <http://www.apache.org/>.
286N/A */
286N/A
286N/Aimport com.sun.org.apache.bcel.internal.Constants;
286N/Aimport com.sun.org.apache.bcel.internal.classfile.Utility;
286N/Aimport com.sun.org.apache.bcel.internal.classfile.ConstantPool;
286N/Aimport java.io.*;
286N/Aimport com.sun.org.apache.bcel.internal.util.ByteSequence;
286N/A
286N/A/**
286N/A * Abstract super class for all Java byte codes.
286N/A *
286N/A * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
286N/A */
286N/Apublic abstract class Instruction implements Cloneable, Serializable {
286N/A protected short length = 1; // Length of instruction in bytes
286N/A protected short opcode = -1; // Opcode number
286N/A
286N/A private static InstructionComparator cmp = InstructionComparator.DEFAULT;
286N/A
286N/A /**
286N/A * Empty constructor needed for the Class.newInstance() statement in
286N/A * Instruction.readInstruction(). Not to be used otherwise.
286N/A */
286N/A Instruction() {}
286N/A
286N/A public Instruction(short opcode, short length) {
286N/A this.length = length;
286N/A this.opcode = opcode;
286N/A }
286N/A
286N/A /**
286N/A * Dump instruction as byte code to stream out.
286N/A * @param out Output stream
286N/A */
286N/A public void dump(DataOutputStream out) throws IOException {
286N/A out.writeByte(opcode); // Common for all instructions
286N/A }
286N/A
286N/A /** @return name of instruction, i.e., opcode name
286N/A */
286N/A public String getName() {
286N/A return Constants.OPCODE_NAMES[opcode];
286N/A }
286N/A
286N/A /**
286N/A * Long output format:
286N/A *
286N/A * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]"
286N/A * "("&lt;length of instruction&gt;")"
286N/A *
286N/A * @param verbose long/short format switch
286N/A * @return mnemonic for instruction
286N/A */
286N/A public String toString(boolean verbose) {
286N/A if(verbose)
286N/A return getName() + "[" + opcode + "](" + length + ")";
286N/A else
286N/A return getName();
286N/A }
286N/A
286N/A /**
286N/A * @return mnemonic for instruction in verbose format
286N/A */
286N/A public String toString() {
286N/A return toString(true);
286N/A }
286N/A
286N/A /**
286N/A * @return mnemonic for instruction with sumbolic references resolved
286N/A */
286N/A public String toString(ConstantPool cp) {
286N/A return toString(false);
286N/A }
286N/A
286N/A /**
286N/A * Use with caution, since `BranchInstruction's have a `target' reference which
286N/A * is not copied correctly (only basic types are). This also applies for
286N/A * `Select' instructions with their multiple branch targets.
286N/A *
286N/A * @see BranchInstruction
286N/A * @return (shallow) copy of an instruction
286N/A */
286N/A public Instruction copy() {
286N/A Instruction i = null;
286N/A
286N/A // "Constant" instruction, no need to duplicate
286N/A if(InstructionConstants.INSTRUCTIONS[this.getOpcode()] != null)
286N/A i = this;
286N/A else {
286N/A try {
286N/A i = (Instruction)clone();
286N/A } catch(CloneNotSupportedException e) {
286N/A System.err.println(e);
286N/A }
286N/A }
286N/A
286N/A return i;
286N/A }
286N/A
286N/A /**
286N/A * Read needed data (e.g. index) from file.
286N/A *
286N/A * @param bytes byte sequence to read from
286N/A * @param wide "wide" instruction flag
286N/A */
286N/A protected void initFromFile(ByteSequence bytes, boolean wide)
286N/A throws IOException
286N/A {}
286N/A
286N/A /**
286N/A * Read an instruction from (byte code) input stream and return the
286N/A * appropiate object.
286N/A *
286N/A * @param file file to read from
286N/A * @return instruction object being read
286N/A */
286N/A public static final Instruction readInstruction(ByteSequence bytes)
286N/A throws IOException
286N/A {
286N/A boolean wide = false;
286N/A short opcode = (short)bytes.readUnsignedByte();
286N/A Instruction obj = null;
286N/A
286N/A if(opcode == Constants.WIDE) { // Read next opcode after wide byte
286N/A wide = true;
286N/A opcode = (short)bytes.readUnsignedByte();
286N/A }
286N/A
286N/A if(InstructionConstants.INSTRUCTIONS[opcode] != null)
286N/A return InstructionConstants.INSTRUCTIONS[opcode]; // Used predefined immutable object, if available
286N/A
286N/A /* Find appropiate class, instantiate an (empty) instruction object
286N/A * and initialize it by hand.
286N/A */
286N/A Class clazz;
286N/A
286N/A try {
286N/A clazz = Class.forName(className(opcode));
286N/A } catch (ClassNotFoundException cnfe){
286N/A // If a class by that name does not exist, the opcode is illegal.
286N/A // Note that IMPDEP1, IMPDEP2, BREAKPOINT are also illegal in a sense.
286N/A throw new ClassGenException("Illegal opcode detected.");
286N/A }
286N/A
286N/A try {
286N/A obj = (Instruction)clazz.newInstance();
286N/A
286N/A if(wide && !((obj instanceof LocalVariableInstruction) ||
286N/A (obj instanceof IINC) ||
286N/A (obj instanceof RET)))
286N/A throw new Exception("Illegal opcode after wide: " + opcode);
286N/A
286N/A obj.setOpcode(opcode);
286N/A obj.initFromFile(bytes, wide); // Do further initializations, if any
286N/A // Byte code offset set in InstructionList
286N/A } catch(Exception e) { throw new ClassGenException(e.toString()); }
286N/A
286N/A return obj;
286N/A }
286N/A
286N/A private static final String className(short opcode) {
286N/A String name = Constants.OPCODE_NAMES[opcode].toUpperCase();
286N/A
286N/A /* ICONST_0, etc. will be shortened to ICONST, etc., since ICONST_0 and the like
286N/A * are not implemented (directly).
286N/A */
286N/A try {
286N/A int len = name.length();
286N/A char ch1 = name.charAt(len - 2), ch2 = name.charAt(len - 1);
286N/A
286N/A if((ch1 == '_') && (ch2 >= '0') && (ch2 <= '5'))
286N/A name = name.substring(0, len - 2);
286N/A
286N/A if(name.equals("ICONST_M1")) // Special case
286N/A name = "ICONST";
286N/A } catch(StringIndexOutOfBoundsException e) { System.err.println(e); }
286N/A
286N/A return "com.sun.org.apache.bcel.internal.generic." + name;
286N/A }
286N/A
286N/A /**
286N/A * This method also gives right results for instructions whose
286N/A * effect on the stack depends on the constant pool entry they
286N/A * reference.
286N/A * @return Number of words consumed from stack by this instruction,
286N/A * or Constants.UNPREDICTABLE, if this can not be computed statically
286N/A */
286N/A public int consumeStack(ConstantPoolGen cpg) {
286N/A return Constants.CONSUME_STACK[opcode];
286N/A }
286N/A
286N/A /**
286N/A * This method also gives right results for instructions whose
286N/A * effect on the stack depends on the constant pool entry they
286N/A * reference.
286N/A * @return Number of words produced onto stack by this instruction,
286N/A * or Constants.UNPREDICTABLE, if this can not be computed statically
286N/A */
286N/A public int produceStack(ConstantPoolGen cpg) {
286N/A return Constants.PRODUCE_STACK[opcode];
286N/A }
286N/A
286N/A /**
286N/A * @return this instructions opcode
286N/A */
286N/A public short getOpcode() { return opcode; }
286N/A
286N/A /**
286N/A * @return length (in bytes) of instruction
286N/A */
286N/A public int getLength() { return length; }
286N/A
286N/A /**
286N/A * Needed in readInstruction.
286N/A */
286N/A private void setOpcode(short opcode) { this.opcode = opcode; }
286N/A
286N/A /** Some instructions may be reused, so don't do anything by default.
286N/A */
286N/A void dispose() {}
286N/A
286N/A /**
286N/A * Call corresponding visitor method(s). The order is:
286N/A * Call visitor methods of implemented interfaces first, then
286N/A * call methods according to the class hierarchy in descending order,
286N/A * i.e., the most specific visitXXX() call comes last.
286N/A *
286N/A * @param v Visitor object
286N/A */
286N/A public abstract void accept(Visitor v);
286N/A
286N/A /** Get Comparator object used in the equals() method to determine
286N/A * equality of instructions.
286N/A *
286N/A * @return currently used comparator for equals()
286N/A */
286N/A public static InstructionComparator getComparator() { return cmp; }
286N/A
286N/A /** Set comparator to be used for equals().
286N/A */
286N/A public static void setComparator(InstructionComparator c) { cmp = c; }
286N/A
286N/A /** Check for equality, delegated to comparator
286N/A * @return true if that is an Instruction and has the same opcode
286N/A */
286N/A public boolean equals(Object that) {
286N/A return (that instanceof Instruction)?
286N/A cmp.equals(this, (Instruction)that) : false;
286N/A }
286N/A}