content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  package jaxp.sun.org.apache.bcel.internal.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 jaxp.sun.org.apache.bcel.internal.Constants;
  import jaxp.sun.org.apache.bcel.internal.classfile.ConstantPool;
  import java.io.*;
  import jaxp.sun.org.apache.bcel.internal.util.ByteSequence;
  
  /**
   * Abstract super class for all Java byte codes.
   *
   * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
   */
  public abstract class Instruction implements Cloneable, Serializable {
    protected short length = 1;  // Length of instruction in bytes
    protected short opcode = -1; // Opcode number
  
    private static InstructionComparator cmp = InstructionComparator.DEFAULT;
  
    /**
     * Empty constructor needed for the Class.newInstance() statement in
     * Instruction.readInstruction(). Not to be used otherwise.
     */
    Instruction() {}
  
    public Instruction(short opcode, short length) {
      this.length = length;
      this.opcode = opcode;
    }
  
    /**
     * Dump instruction as byte code to stream out.
     * @param out Output stream
     */
    public void dump(DataOutputStream out) throws IOException {
      out.writeByte(opcode); // Common for all instructions
    }
  
    /** @return name of instruction, i.e., opcode name
     */
    public String getName() {
      return Constants.OPCODE_NAMES[opcode];
    }
  
    /**
     * Long output format:
     *
     * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]"
     * "("&lt;length of instruction&gt;")"
     *
     * @param verbose long/short format switch
     * @return mnemonic for instruction
     */
    public String toString(boolean verbose) {
      if(verbose)
        return getName() + "[" + opcode + "](" + length + ")";
      else
        return getName();
    }
  
    /**
     * @return mnemonic for instruction in verbose format
     */
    public String toString() {
      return toString(true);
    }
  
    /**
     * @return mnemonic for instruction with sumbolic references resolved
     */
    public String toString(ConstantPool cp) {
      return toString(false);
    }
  
    /**
     * 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.
     *
     * @see BranchInstruction
     * @return (shallow) copy of an instruction
     */
    public Instruction copy() {
      Instruction i = null;
  
      // "Constant" instruction, no need to duplicate
      if(InstructionConstants.INSTRUCTIONS[this.getOpcode()] != null)
        i = this;
      else {
        try {
          i = (Instruction)clone();
        } catch(CloneNotSupportedException e) {
          System.err.println(e);
        }
      }
  
      return i;
    }
  
    /**
     * Read needed data (e.g. index) from file.
     *
     * @param bytes byte sequence to read from
     * @param wide "wide" instruction flag
     */
    protected void initFromFile(ByteSequence bytes, boolean wide)
      throws IOException
    {}
  
    /**
     * Read an instruction from (byte code) input stream and return the
     * appropiate 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();
      Instruction obj    = null;
  
      if(opcode == Constants.WIDE) { // Read next opcode after wide byte
        wide = true;
        opcode  = (short)bytes.readUnsignedByte();
      }
  
      if(InstructionConstants.INSTRUCTIONS[opcode] != null)
        return InstructionConstants.INSTRUCTIONS[opcode]; // Used predefined immutable object, if available
  
      /* Find appropiate class, instantiate an (empty) instruction object
       * and initialize it by hand.
       */
      Class clazz;
  
      try {
        clazz = Class.forName(className(opcode));
      } catch (ClassNotFoundException cnfe){
        // If a class by that name does not exist, the opcode is illegal.
        // Note that IMPDEP1, IMPDEP2, BREAKPOINT are also illegal in a sense.
        throw new ClassGenException("Illegal opcode detected.");
      }
  
      try {
        obj = (Instruction)clazz.newInstance();
  
        if(wide && !((obj instanceof LocalVariableInstruction) ||
                     (obj instanceof IINC) ||
                     (obj instanceof RET)))
          throw new Exception("Illegal opcode after wide: " + opcode);
  
        obj.setOpcode(opcode);
        obj.initFromFile(bytes, wide); // Do further initializations, if any
        // Byte code offset set in InstructionList
      } catch(Exception e) { throw new ClassGenException(e.toString()); }
  
      return obj;
    }
  
    private static final String className(short opcode) {
      String name = Constants.OPCODE_NAMES[opcode].toUpperCase();
  
      /* ICONST_0, etc. will be shortened to ICONST, etc., since ICONST_0 and the like
       * are not implemented (directly).
       */
      try {
        int  len = name.length();
        char ch1 = name.charAt(len - 2), ch2 = name.charAt(len - 1);
  
        if((ch1 == '_') && (ch2 >= '0')  && (ch2 <= '5'))
          name = name.substring(0, len - 2);
  
        if(name.equals("ICONST_M1")) // Special case
          name = "ICONST";
      } catch(StringIndexOutOfBoundsException e) { System.err.println(e); }
  
      return "jaxp.sun.org.apache.bcel.internal.generic." + name;
    }
  
    /**
     * This method also gives right results for instructions whose
     * effect on the stack depends on the constant pool entry they
     * reference.
     *  @return Number of words consumed from stack by this instruction,
     * or Constants.UNPREDICTABLE, if this can not be computed statically
     */
    public int consumeStack(ConstantPoolGen cpg) {
      return Constants.CONSUME_STACK[opcode];
    }
  
    /**
     * This method also gives right results for instructions whose
     * effect on the stack depends on the constant pool entry they
     * reference.
     * @return Number of words produced onto stack by this instruction,
     * or Constants.UNPREDICTABLE, if this can not be computed statically
     */
    public int produceStack(ConstantPoolGen cpg) {
      return Constants.PRODUCE_STACK[opcode];
    }
  
    /**
     * @return this instructions opcode
     */
    public short getOpcode()    { return opcode; }
  
    /**
     * @return length (in bytes) of instruction
     */
    public int getLength()   { return length; }
  
    /**
     * Needed in readInstruction.
     */
    private void setOpcode(short opcode) { this.opcode = opcode; }
  
    /** Some instructions may be reused, so don't do anything by default.
     */
    void dispose() {}
  
    /**
     * Call corresponding visitor method(s). The order is:
     * Call visitor methods of implemented interfaces first, then
     * call methods according to the class hierarchy in descending order,
     * i.e., the most specific visitXXX() call comes last.
     *
     * @param v Visitor object
     */
    public abstract void accept(Visitor v);
  
    /** Get Comparator object used in the equals() method to determine
     * equality of instructions.
     *
     * @return currently used comparator for equals()
     */
    public static InstructionComparator getComparator() { return cmp; }
  
    /** Set comparator to be used for equals().
     */
    public static void setComparator(InstructionComparator c) { cmp = c; }
  
    /** Check for equality, delegated to comparator
     * @return true if that is an Instruction and has the same opcode
     */
    public boolean equals(Object that) {
      return (that instanceof Instruction)?
        cmp.equals(this, (Instruction)that) : false;
    }
  }
  