gt:             int from = (opcode-opc_i2l)/3;
context: /* Opcodes Copyright (C) 1999-2002 Jochen Hoenicke.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation; either version 2, or (at your option)
   * any later version.
   *
   * This program 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 Lesser General Public License
   * along with this program; see the file COPYING.LESSER.  If not, write to
   * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   * $Id: Opcodes.java,v 1.18.2.1 2002/05/28 17:34:03 hoenicke Exp $
   */
  
  package jode.decompiler;
  import jode.type.Type;
  import jode.type.IntegerType;
  import jode.type.MethodType;
  import jode.expr.*;
  import jode.flow.*;
  import jode.bytecode.*;
  import java.io.*;
  import java.util.Vector;
  
  /**
   * This is an abstract class which creates flow blocks for the
   * opcodes in a byte stream.
   */
  public abstract class Opcodes implements jode.bytecode.Opcodes {
  
      private final static Type tIntHint
  	= new IntegerType(IntegerType.IT_I,
  			  IntegerType.IT_I
  			  | IntegerType.IT_B
  			  | IntegerType.IT_C
  			  | IntegerType.IT_S);
      private final static Type tBoolIntHint
  	= new IntegerType(IntegerType.IT_I
  			  | IntegerType.IT_Z,
  			  IntegerType.IT_I
  			  | IntegerType.IT_B
  			  | IntegerType.IT_C
  			  | IntegerType.IT_S
  			  | IntegerType.IT_Z);
  
      private final static int LOCAL_TYPES = 0;
      private final static int ARRAY_TYPES = 1;
      private final static int UNARY_TYPES = 2;
      private final static int I2BCS_TYPES = 3;
      private final static int BIN_TYPES   = 4;
      private final static int ZBIN_TYPES  = 5;
  
      private final static Type types[][] = {
  	// Local types
          { Type.tBoolUInt, Type.tLong, Type.tFloat, Type.tDouble, 
  	  Type.tUObject },
  	// Array types
          { Type.tInt, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject, 
            Type.tBoolByte, Type.tChar, Type.tShort },
  	// ifld2ifld and shl types
          { Type.tInt, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject },
  	// i2bcs types
          { Type.tByte, Type.tChar, Type.tShort },
  	// cmp/add/sub/mul/div types
          { tIntHint, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject },
  	// and/or/xor types
          { tBoolIntHint, Type.tLong, Type.tFloat, Type.tDouble, Type.tUObject }
      };
      
      private static StructuredBlock createNormal(MethodAnalyzer ma, 
  						Instruction instr,
  						Expression expr)
      {
          return new InstructionBlock(expr, new Jump(FlowBlock.NEXT_BY_ADDR));
      }
  
      private static StructuredBlock createSpecial(MethodAnalyzer ma, 
  						 Instruction instr,
  						 int type, 
  						 int stackcount, int param)
      {
          return new SpecialBlock(type, stackcount, param, 
  				new Jump(FlowBlock.NEXT_BY_ADDR));
      }
  
      private static StructuredBlock createGoto(MethodAnalyzer ma,
                                                Instruction instr)
      {
          return new EmptyBlock
  	    (new Jump((FlowBlock)instr.getSingleSucc().getTmpInfo()));
      }
  
      private static StructuredBlock createJsr(MethodAnalyzer ma, 
  					     Instruction instr)
      {
          return new JsrBlock
  	    (new Jump((FlowBlock)instr.getSingleSucc().getTmpInfo()),
  	     new Jump(FlowBlock.NEXT_BY_ADDR));
      }
  
      private static StructuredBlock createIfGoto(MethodAnalyzer ma, 
  						Instruction instr,
  						Expression expr)
      {
          return new ConditionalBlock
  	    (expr, new Jump((FlowBlock)instr.getSingleSucc().getTmpInfo()), 
  	     new Jump(FlowBlock.NEXT_BY_ADDR));
      }
  
      private static StructuredBlock createSwitch(MethodAnalyzer ma,
  						Instruction instr,
                                                  int[] cases, FlowBlock[] dests)
      {
          return new SwitchBlock(new NopOperator(Type.tUInt), cases, dests);
      }
  
      private static StructuredBlock createBlock(MethodAnalyzer ma,
                                                 Instruction instr,
                                                 StructuredBlock block)
      {
          return block;
      }
  
      private static StructuredBlock createRet(MethodAnalyzer ma,
  					     Instruction instr,
  					     LocalInfo local)
      {
  	return new RetBlock(local);
      }
  
      /**
       * Read an opcode out of a data input stream containing the bytecode.
       * @param addr    The current address.
       * @param stream  The stream containing the java byte code.
       * @param ma      The Method Analyzer 
       *                (where further information can be get from).
       * @return The FlowBlock representing this opcode
       *         or null if the stream is empty.
       * @exception IOException  if an read error occured.
       * @exception ClassFormatError  if an invalid opcode is detected.
       */
      public static StructuredBlock readOpcode(Instruction instr, 
  					     MethodAnalyzer ma)
          throws ClassFormatError
      {
          int opcode = instr.getOpcode();
          switch (opcode) {
          case opc_nop:
              return createBlock(ma, instr, new EmptyBlock
  			       (new Jump(FlowBlock.NEXT_BY_ADDR)));
          case opc_ldc:
          case opc_ldc2_w:
              return createNormal (ma, instr, 
  				 new ConstOperator(instr.getConstant()));
  
          case opc_iload: case opc_lload: 
          case opc_fload: case opc_dload: case opc_aload:
              return createNormal
                  (ma, instr, new LocalLoadOperator
                   (types[LOCAL_TYPES][opcode-opc_iload], ma,
                    ma.getLocalInfo(instr.getAddr(), instr.getLocalSlot())));
          case opc_iaload: case opc_laload: 
          case opc_faload: case opc_daload: case opc_aaload:
          case opc_baload: case opc_caload: case opc_saload:
              return createNormal
                  (ma, instr, new ArrayLoadOperator
                   (types[ARRAY_TYPES][opcode - opc_iaload]));
          case opc_istore: case opc_lstore: 
          case opc_fstore: case opc_dstore: case opc_astore:
              return createNormal
                  (ma, instr, new StoreInstruction
  		 (new LocalStoreOperator
  		  (types[LOCAL_TYPES][opcode-opc_istore], 
  		   ma.getLocalInfo(instr.getNextByAddr().getAddr(), 
  				   instr.getLocalSlot()))));
          case opc_iastore: case opc_lastore:
          case opc_fastore: case opc_dastore: case opc_aastore:
          case opc_bastore: case opc_castore: case opc_sastore:
              return createNormal
                  (ma, instr, new StoreInstruction
  		 (new ArrayStoreOperator
  		  (types[ARRAY_TYPES][opcode - opc_iastore])));
          case opc_pop: case opc_pop2:
              return createSpecial
                  (ma, instr, SpecialBlock.POP, opcode - opc_pop + 1, 0);
          case opc_dup: case opc_dup_x1: case opc_dup_x2:
          case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
              return createSpecial
                  (ma, instr, SpecialBlock.DUP, 
                   (opcode - opc_dup)/3+1, (opcode - opc_dup)%3);
          case opc_swap:
              return createSpecial(ma, instr, SpecialBlock.SWAP, 1, 0);
          case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
          case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
          case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
          case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
          case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
              return createNormal
                  (ma, instr, new BinaryOperator
                   (types[BIN_TYPES][(opcode - opc_iadd)%4],
                    (opcode - opc_iadd)/4+Operator.ADD_OP));
          case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
              return createNormal
                  (ma, instr, new UnaryOperator
                   (types[UNARY_TYPES][opcode - opc_ineg], Operator.NEG_OP));
          case opc_ishl: case opc_lshl:
          case opc_ishr: case opc_lshr:
          case opc_iushr: case opc_lushr:
              return createNormal
                  (ma, instr, new ShiftOperator
                   (types[UNARY_TYPES][(opcode - opc_ishl)%2],
                    (opcode - opc_ishl)/2 + Operator.SHIFT_OP));
          case opc_iand: case opc_land:
          case opc_ior : case opc_lor :
          case opc_ixor: case opc_lxor:
              return createNormal
                  (ma, instr, new BinaryOperator
                   (types[ZBIN_TYPES][(opcode - opc_iand)%2],
                    (opcode - opc_iand)/2 + Operator.AND_OP));
          case opc_iinc: {
              int value = instr.getIncrement();
              int operation = Operator.ADD_OP;
              if (value < 0) {
                  value = -value;
                  operation = Operator.SUB_OP;
              }
              LocalInfo li
  		= ma.getLocalInfo(instr.getAddr(), instr.getLocalSlot());
              return createNormal
                  (ma, instr, new IIncOperator
                   (new LocalStoreOperator(Type.tInt, li), 
  		  value, operation + Operator.OPASSIGN_OP));
          }
          case opc_i2l: case opc_i2f: case opc_i2d:
          case opc_l2i: case opc_l2f: case opc_l2d:
          case opc_f2i: case opc_f2l: case opc_f2d:
          case opc_d2i: case opc_d2l: case opc_d2f: {
  