import org.apache.bcel.Repository;
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.*;
import org.apache.bcel.Constants;
import org.apache.bcel.*;
import java.util.*;
import java.io.*;

/**
 * 
 * This is a disassembler for java BYTECODE...
 *
 * @author Matthew W. Coan (April 13, 2019)
 *
 */
public class disasm implements InstructionConstants {
   private static String class_name = "";
   private PrintStream fout = null;
   private int index0 = 0;
   private String _package = "";
   private TreeMap< String, MyCode > code_map = new TreeMap< String, MyCode >();
   private ConstantPoolGen gcp = null;
   private String the_class_name = "";
   private ConstantPool cp = null;
   private String rt = "rt\\";

   public disasm(String rt) {
      this.rt = rt;
   }

   public static void main(String args[]) throws Exception {
      String rt = "rt\\";
      for(int i = 0; i < args.length; i++) {
         if(args[i].equals("-rt")) {
            if((i+1) < args.length) {
               i++;
               rt = args[i];
            }
         }
      }
      disasm code = new disasm(rt);
      code.run(args);
   }

   public class MyCode {
      public void run(Instruction instruction) {

      }
   }

   public class invokedynamic extends MyCode {
      public void run(Instruction instruction) {
         INVOKEDYNAMIC id = (INVOKEDYNAMIC)instruction;
         fout.println("invokedynamic " + id.getIndex());
      }
   }

   public class invokestatic extends MyCode {
      public void run(Instruction instruction) {
         Type tt[] = null;
         InvokeInstruction ii0 = (InvokeInstruction)instruction;
         tt = ii0.getArgumentTypes(gcp);
         String cls_vec[] = new String[tt.length];
         for(int k = 0; k < cls_vec.length; k++) {
            cls_vec[k] = tt[k].getSignature();
         }
         String sig3 = "";
         for(int k = 0; k < tt.length; k++) {
            sig3 += (tt[k].getSignature());
         }
         String cls0 = ii0.getClassName(gcp);
         String method = ii0.getMethodName(gcp);
         String return_type = "void";

         Method m = get_static_method(cls0,method,cls_vec);
         String signature = m.getSignature();
         return_type = m.getReturnType().toString();

         String temp_args = cls0
                     + " " + method
                     + " (" + sig3 + ")" + toASM(return_type)
                     + " " + tt.length;
         fout.println(instruction.getName() + " " + temp_args);
      }
   }

   public class invokevirtual extends MyCode {
      public void run(Instruction instruction) {
         INVOKEVIRTUAL ii0 = (INVOKEVIRTUAL)instruction;
         Type tt[] = ii0.getArgumentTypes(gcp);
         String sig3 = "";
         String sig_array[] = new String[tt.length];
         for(int k = 0; k < sig_array.length; k++) {
            sig_array[k] = tt[k].getSignature();
         }
         for(int k = 0; k < tt.length; k++) {
            sig3 += (tt[k].getSignature());
         }
         String cls0 = ii0.getClassName(gcp);
         String method = ii0.getMethodName(gcp);
         //java.lang.reflect.Method the_method = null;
         String return_type = "void";

         Method m = get_method(cls0,method,sig_array);
         String signature = m.getSignature();
         return_type = m.getReturnType().toString();

         String temp_args = cls0
                     + " " + method  
                     + " (" + sig3 + ")" + toASM(return_type)
                     + " " + tt.length;
         fout.println("invokevirtual " + temp_args);
      }
   }

   public class invokespecial extends MyCode {
      public void run(Instruction instruction) {
         INVOKESPECIAL in = (INVOKESPECIAL)instruction;
         String method = in.getMethodName(gcp);
         Type tt[] = in.getArgumentTypes(gcp);

         String sig3 = "";
         String cls_array[] = new String[tt.length];

         for(int k = 0; k < tt.length; k++) {
            sig3 += tt[k].getSignature();
            cls_array[k] = tt[k].getSignature();
         }

         String cls0 = in.getClassName(gcp);
         //java.lang.reflect.Method the_method = null;
         String return_type = "void";

         Method m = get_method(cls0,method,cls_array);
         String signature = m.getSignature();
         return_type = m.getReturnType().toString();

         String temp_args = null;
         if(m != null) {
            temp_args = cls0
                        + " " + method
                        + " (" + sig3 + ")" + toASM(return_type)
                        + " " + tt.length;
         }
         else {
            temp_args = cls0
                        + " " + method
                        + " ()V" + 0;
         }
         fout.println("invokespecial " + temp_args);
      }
   }

   public class invokeinterface extends MyCode {
      public void run(Instruction instruction) {
         INVOKEINTERFACE ii0 = (INVOKEINTERFACE)instruction;
         Type tt[] = ii0.getArgumentTypes(gcp);
         String cls_vec[] = new String[tt.length];
         for(int k = 0; k < cls_vec.length; k++) {
            cls_vec[k] = tt[k].getSignature();
         }
         String sig3 = "";
         for(int k = 0; k < tt.length; k++) {
            sig3 += (tt[k].getSignature());
         }
         String cls0 = ii0.getClassName(gcp);
         String method = ii0.getMethodName(gcp);
         String return_type = "void";

         Method m = get_method(cls0,method,cls_vec);
         String signature = m.getSignature();
         return_type = m.getReturnType().toString();

         String temp_args = cls0
                     + " " + method
                     + " (" + sig3 + ")" + toASM(return_type)
                     + " " + tt.length;
         fout.println(instruction.getName() + " " + temp_args);         
      }
   }

   public class Goto extends MyCode {
      public void run(Instruction instruction) {
         BranchInstruction b = (BranchInstruction)instruction;
         String temp_args = "L" + (b.getTarget().getPosition());
         fout.println("goto " + temp_args);
      }
   }

   public class Instanceof extends MyCode {
      public void run(Instruction instruction) {
         INSTANCEOF inst = (INSTANCEOF)instruction;
         fout.println("instanceof " + inst.getType(gcp).toString());
      }
   }

   public class Getfield extends MyCode {
      public void run(Instruction instruction) {
         GETFIELD gf = (GETFIELD)instruction;
         String temp_args = gf.getClassName(gcp)
                           + " " + gf.getName(gcp)
                           + " " + gf.getSignature(gcp);
         fout.println("fieldref " + temp_args + " temp");
         fout.println("\tgetfield " + temp_args);
      }
   }

   public class Putfield extends MyCode {
      public void run(Instruction instruction) {
         PUTFIELD gf = (PUTFIELD)instruction;
         String temp_args = gf.getClassName(gcp)
                     + " " + gf.getName(gcp)
                     + " " + gf.getSignature(gcp);
         fout.println("fieldref " + temp_args + " temp");
         fout.println("\tputfield " + temp_args);
      }
   }

   public class Getstatic extends MyCode {
      public void run(Instruction instruction) {
         GETSTATIC gf = (GETSTATIC)instruction;
         String temp_args = gf.getClassName(gcp)
                     + " " + gf.getName(gcp)
                     + " " + gf.getSignature(gcp);
         fout.println("fieldref " + temp_args + " temp");
         fout.println("\tgetstatic " + temp_args);
      }
   }

   public class Putstatic extends MyCode {
      public void run(Instruction instruction) {
         PUTSTATIC gf = (PUTSTATIC)instruction;
         String temp_args = gf.getClassName(gcp)
                     + " " + gf.getName(gcp)
                     + " " + gf.getSignature(gcp);
         fout.println("fieldref " + temp_args + " temp");
         fout.println("\tputstatic " + temp_args);
      }
   }

   public class New extends MyCode {
      public void run(Instruction instruction) {
         NEW n = (NEW)instruction;
         int index1 = n.getIndex();
         Constant c = cp.getConstant(index1);
         String temp_args = cp.constantToString(c);
         fout.println("new_op " + temp_args);
      }
   }

   public class Anewarray extends MyCode {
      public void run(Instruction instruction) {
         ANEWARRAY n = (ANEWARRAY)instruction;
         fout.println("anewarray " + n.getIndex());
      }
   }

   public class Newarray extends MyCode {
      public void run(Instruction instruction) {
         NEWARRAY n = (NEWARRAY)instruction;
         fout.println("newarray " + n.getTypecode());
      }
   }

   public class checkcast extends MyCode {
      public void run(Instruction instruction) {
         CHECKCAST n = (CHECKCAST)instruction;
         fout.println("checkcast "+n.getType(gcp).toString());
      }
   }

   public class tableswitch extends MyCode {
      public void run(Instruction instruction) {
         TABLESWITCH sw = (TABLESWITCH)instruction;
         int match[] = sw.getMatchs();
         InstructionHandle targets[] = sw.getTargets();
         StringBuffer buffer = new StringBuffer();
         for(int i0 = 0; i0 < match.length; i0++) {
            buffer.append(match[i0]+",");
         }
         StringBuffer buffer2 = new StringBuffer();
         for(int i0 = 0; i0 < targets.length; i0++) {
            buffer2.append("L"+targets[i0].getPosition()+",");
         } 
         fout.println("tableswitch "
                        + buffer.toString() + " " 
                        + buffer2.toString() + " "
                        + "L" + sw.getTarget().getPosition());
      }
   }

   public class lookupswitch extends MyCode {
      public void run(Instruction instruction) {
         LOOKUPSWITCH sw = (LOOKUPSWITCH)instruction;
         int match[] = sw.getMatchs();
         InstructionHandle targets[] = sw.getTargets();
         StringBuffer buffer = new StringBuffer();
         for(int i0 = 0; i0 < match.length; i0++) {
            buffer.append(match[i0]+",");
         }
         StringBuffer buffer2 = new StringBuffer();
         for(int i0 = 0; i0 < targets.length; i0++) {
            buffer2.append("L"+targets[i0].getPosition()+",");
         }
         fout.println("lookupswitch "
                        + buffer.toString() + " "
                        + buffer2.toString() + " "
                        + "L" + sw.getTarget().getPosition());
      }
   }

   public class iinc extends MyCode {
      public void run(Instruction instruction) {
         IINC n = (IINC)instruction;
         String temp_args = "temp" + n.getIndex() + " " + n.getIncrement();
         fout.println("iinc " + temp_args);
      }
   }

   public class If extends MyCode {
      public void run(Instruction instruction) {
         BranchInstruction b = (BranchInstruction)instruction;
         String temp_args = "L" + (b.getTarget().getPosition());
         fout.println(b.getName() + " " + temp_args);
      }
   }

   public class Return extends MyCode {
      public void run(Instruction instruction) {
         fout.println("return");
      }
   }

   public class freturn extends MyCode {
      public void run(Instruction instruction) {
         fout.println("freturn");
      }
   }
   public class dreturn extends MyCode {
      public void run(Instruction instruction) {
         fout.println("dreturn");
      }
   }
   public class lreturn extends MyCode {
      public void run(Instruction instruction) {
         fout.println("lreturn");
      }
   }
   public class ireturn extends MyCode {
      public void run(Instruction instruction) {
         fout.println("ireturn");
      }
   }
   public class areturn extends MyCode {
      public void run(Instruction instruction) {
         fout.println("areturn");
      }
   }
   public class Pop extends MyCode {
      public void run(Instruction instruction) {
         fout.println("pop");
      }
   }
   public class ldc2_w extends MyCode {
      public void run(Instruction instruction) {
         LDC2_W ldc = (LDC2_W)instruction;
         int index1 = ldc.getIndex();
         Constant c = cp.getConstant(index1);
         String temp = cp.constantToString(c);
         String arg = ldc.getType(gcp).toString();
         if(arg.equals("double")) {
            fout.println("ldc_double " + temp);
         }
         else if(arg.equals("long")) {
            fout.println("ldc_long " + temp);
         }
      }
   }
   public class caload extends MyCode {
      public void run(Instruction instruction) {
         CALOAD in = (CALOAD)instruction;
         fout.println("caload");
      }
   }
   public class dload extends MyCode {
      public void run(Instruction instruction) {
         DLOAD in = (DLOAD)instruction;
         fout.println("dload temp" + in.getIndex());
      }
   }
   public class iaload extends MyCode {
      public void run(Instruction instruction) {
         IALOAD il = (IALOAD)instruction;
         fout.println("iaload");
      }
   }
   public class daload extends MyCode {
      public void run(Instruction instruction) {
         DALOAD il = (DALOAD)instruction;
         fout.println("daload");
      }
   }
   public class faload extends MyCode {
      public void run(Instruction instruction) {
         FALOAD il = (FALOAD)instruction;
         fout.println("faload");
      }
   }
   public class lload extends MyCode {
      public void run(Instruction instruction) {
         LLOAD il = (LLOAD)instruction;
         fout.println("lload temp" + il.getIndex());
      }
   }
   public class iload extends MyCode {
      public void run(Instruction instruction) {
         ILOAD il = (ILOAD)instruction;
         fout.println("iload temp" + il.getIndex());
      }
   }
   public class aaload extends MyCode {
      public void run(Instruction instruction) {
         AALOAD aal = (AALOAD)instruction;
         fout.println("aaload");
      }
   }
   public class aload extends MyCode {
      public void run(Instruction instruction) {
         ALOAD al = (ALOAD)instruction;
         fout.println("aload temp"+al.getIndex());
      }
   }
   public class baload extends MyCode {
      public void run(Instruction instruction) {
         BALOAD al = (BALOAD)instruction;
         fout.println("baload");
      }
   }
   public class castore extends MyCode {
      public void run(Instruction instruction) {
         CASTORE li = (CASTORE)instruction;
         fout.println(instruction.getName());
      }
   }
   public class laload extends MyCode {
      public void run(Instruction instruction) {
         LALOAD li = (LALOAD)instruction;
         fout.println(instruction.getName());
      }
   }
   public class saload extends MyCode {
      public void run(Instruction instruction) {
         SALOAD li = (SALOAD)instruction;
         fout.println(instruction.getName());
      }
   }
   public class astore extends MyCode {
      public void run(Instruction instruction) {
         ASTORE as = (ASTORE)instruction;
         fout.println("astore temp"+as.getIndex());
      }
   }
   public class aastore extends MyCode {
      public void run(Instruction instruction) {
         AASTORE aas = (AASTORE)instruction;
         fout.println("aastore");
      }
   }
   public class iastore extends MyCode {
      public void run(Instruction instruction) {
         IASTORE si = (IASTORE)instruction;
         fout.println(instruction.getName());
      }
   }
   public class lastore extends MyCode {
      public void run(Instruction instruction) {
         LASTORE si = (LASTORE)instruction;
         fout.println(instruction.getName());
      }
   }
   public class sastore extends MyCode {
      public void run(Instruction instruction) {
         SASTORE si = (SASTORE)instruction;
         fout.println(instruction.getName());
      }
   }
   public class bastore extends MyCode {
      public void run(Instruction instruction) {
         BASTORE si = (BASTORE)instruction;
         fout.println(instruction.getName());
      }
   }
   public class bipush extends MyCode {
      public void run(Instruction instruction) {
         BIPUSH li = (BIPUSH)instruction;
         fout.println("bipush "+li.getValue().toString());
      }
   }
   public class sipush extends MyCode {
      public void run(Instruction instruction) {
         SIPUSH li = (SIPUSH)instruction;
         fout.println("sipush "+li.getValue().toString());
      }
   }
   public class dastore extends MyCode {
      public void run(Instruction instruction) {
         DASTORE li = (DASTORE)instruction;
         fout.println("dastore");
      }
   }
   public class fastore extends MyCode {
      public void run(Instruction instruction) {
         FASTORE li = (FASTORE)instruction;
         fout.println("fastore");
      }
   }
   public class fload extends MyCode {
      public void run(Instruction instruction) {
         LoadInstruction li = (LoadInstruction)instruction;
         fout.println(instruction.getName() + " temp"+li.getIndex());         
      }
   }

   public String toASM(String str0) {
      String str = str0.replace("[", "");
      str = str.replace("]", "");
      if(str.equals("int"))
         str = "I";
      else if(str.equals("float"))
         str = "F";
      else if(str.equals("long"))
         str = "J";
      else if(str.equals("double"))
         str = "D";
      else if(str.equals("char"))
         str = "C";
      else if(str.equals("boolean"))
         str = "Z";
      else if(str.equals("byte"))
         str = "B";
      else if(str.equals("void"))
         str = "V";
      else if(str.equals("short"))
         str = "S";
      else if(str.indexOf("[") != -1 
              || str.indexOf(";") != -1
              || str.indexOf("/") != -1) {
         str = str.replace(".", "/");
      }
      else {
         str = "L" + str.replace(".", "/") + ";";
      }
      if(str0.indexOf("[") != -1) {
         str = "[" + str;
      }
      return str;
   }

   public boolean isInh(JavaClass interface_array[], String name, String signature) {
      return false;
   }

   public String to_type_signature(String t) {
      String ret = t;
      return ret;
   }

   public String to_class_type(String t) {
      return t;
   }

   public int count_param(String name) {
      return 0;
   }

   public void run(String args[]) throws Exception {
      String cls = null;

      for(int i = 0; i < args.length; i++) {
         if(args[i].equals("-rt")) {
            i++;
            if(i < args.length) {
               rt = args[i];
            }
         }
         else {
            cls = args[i];
         }
      }

      if(cls == null) {
         System.err.print("usage: disasm <java-bytecode>\n");
         System.exit(1);
      }

      the_class_name = cls;

      String fn = cls.replace(".", "_");

      fout = new PrintStream(new FileOutputStream(fn + ".asm"));

      code_map.put("invokedynamic", new invokedynamic());
      code_map.put("invokestatic", new invokestatic());
      code_map.put("invokevirtual", new invokevirtual());
      code_map.put("invokespecial", new invokespecial());
      code_map.put("invokeinterface", new invokeinterface());
      code_map.put("goto", new Goto());
      code_map.put("instanceof", new Instanceof());
      code_map.put("getfield", new Getfield());
      code_map.put("putfield", new Putfield());
      code_map.put("getstatic", new Getstatic());
      code_map.put("putstatic", new Putstatic());
      code_map.put("new", new New());
      code_map.put("anewarray", new Anewarray());
      code_map.put("newarray", new Newarray());
      code_map.put("checkcast", new checkcast());
      code_map.put("tableswitch", new tableswitch());
      code_map.put("lookupswitch", new lookupswitch());
      code_map.put("iinc", new iinc());
      code_map.put("if", new If());
      code_map.put("return", new Return());
      code_map.put("areturn", new areturn());
      code_map.put("ireturn", new ireturn());
      code_map.put("freturn", new freturn());
      code_map.put("dreturn", new dreturn());
      code_map.put("lreturn", new lreturn());
      code_map.put("pop", new Pop());
      code_map.put("ldc2_w", new ldc2_w());
      code_map.put("caload", new caload());
      code_map.put("dload", new dload());
      code_map.put("iaload", new iaload());
      code_map.put("lload", new lload());
      code_map.put("iload", new iload());
      code_map.put("aaload", new aaload());
      code_map.put("aload", new aload());
      code_map.put("baload", new baload());
      code_map.put("castore", new castore());
      code_map.put("laload", new laload());
      code_map.put("sastore", new sastore());
      code_map.put("saload", new saload());
      code_map.put("bastore", new bastore());
      code_map.put("astore", new astore());
      code_map.put("aastore", new aastore());
      code_map.put("iastore", new iastore());
      code_map.put("lastore", new lastore());
      code_map.put("bastore", new bastore());
      code_map.put("sastore", new sastore());
      code_map.put("bipush", new bipush());
      code_map.put("sipush", new sipush());
      code_map.put("daload", new daload());
      code_map.put("faload", new faload());
      code_map.put("dastore", new dastore());
      code_map.put("fastore", new fastore());
      code_map.put("fload", new fload());

      java_2_asm(new String[]{ 
         cls + ".class", 
         cls + ".asm" 
      });

      fout.close();
   }

   public String to_class_name(String name) {
      return name;
   }

   public boolean is_native(String type_name) {
      boolean ret = false;
      if(type_name.equals("byte"))
         ret = true;
      else if(type_name.equals("char"))
         ret = true;
      else if(type_name.equals("short"))
         ret = true;
      else if(type_name.equals("int"))
         ret = true;
      else if(type_name.equals("float"))
         ret = true;
      else if(type_name.equals("double"))
         ret = true;
      else if(type_name.equals("long"))
         ret = true;
      else if(type_name.equals("boolean"))
         ret = true;
      else if(type_name.equals("void"))
         ret = true;
      return ret;
   }

   public Class to_native(String type_name) {
      if(type_name.equals("byte"))
         return byte.class;
      else if(type_name.equals("char"))
         return char.class;
      else if(type_name.equals("short"))
         return short.class;
      else if(type_name.equals("int"))
         return int.class;
      else if(type_name.equals("float"))
         return float.class;
      else if(type_name.equals("dobule"))
         return double.class;
      else if(type_name.equals("long"))
         return long.class;
      else if(type_name.equals("boolean"))
         return boolean.class;
      else if(type_name.equals("void"))
         return void.class;
      return null;
   }

   public String clean(String str) {
      String buffer = new String();
      for(int i = 0; i < str.length(); i++) {
         if(str.charAt(i) == '.') {
            buffer += ".";
         }
         else if(str.charAt(i) == '[') {

         }
         else if(str.charAt(i) == ']') {

         }
         else {
            buffer += str.charAt(i);
         }
      } 
      return buffer;
   }

   public Method get_static_method(String cls0, String m, String args[]) {
      String temp_name = cls0 + ".class";

      temp_name = temp_name.replace(".", "\\");
      temp_name = temp_name.replace("\\class", ".class");

      ClassParser parser = null;
      JavaClass cls = null;

      try {
         parser = new ClassParser(temp_name);
         cls = parser.parse();
      }
      catch(Exception ex) {
         try {
            parser = new ClassParser(rt + temp_name);
            cls = parser.parse();
         }
         catch(Exception ex2) {
            System.err.println("Unable to parse class: " + temp_name);
            System.exit(1);
         }
      }

      Method array[] = cls.getMethods();

      boolean found = false;

      if(array != null) {
         for(int i = 0; i < array.length; i++) {
            if(array[i].getName().equals(m) && array[i].isStatic()) {
               if(array[i].getArgumentTypes().length == args.length) {
/*
                  boolean found2 = false;
                  for(int j = 0; j < array[i].getArgumentTypes().length; j++) {
                     if(args[j].equals(array[i].getArgumentTypes()[j])) {
                        found2 = true;
                     }
                     else {
                        found2 = false;
                        break;
                     }
                  }
                  if(found2) {
*/
                     return array[i];
                 // }
               }
            }
         }
      }
      return null; 
   }

   public Method get_method(String cls0, String m, String args[]) {
//System.err.println("get_method(" + cls0 + "," + m + ")");
      String temp_name = cls0 + ".class";

      temp_name = temp_name.replace(".", "\\");
      temp_name = temp_name.replace("\\class", ".class");

      ClassParser parser = null;
      JavaClass cls = null;

      try {
         parser = new ClassParser(temp_name);
         cls = parser.parse();
      }
      catch(Exception ex) {
         try {
            parser = new ClassParser(rt + temp_name);
            cls = parser.parse();
         }
         catch(Exception ex2) {
            System.err.println("Unable to parse class: " + temp_name);
            System.exit(1);
         }
      }
    
      Method array[] = cls.getMethods();
       
      boolean found = false;

      if(array != null) {
         for(int i = 0; i < array.length; i++) {
//System.out.println(array[i].getName());
            if(array[i].getName().equals(m)) {
               if(array[i].getArgumentTypes().length == args.length) {
                  boolean found2 = false;
/*
                  for(int j = 0; j < array[i].getArgumentTypes().length; j++) {
System.out.println(array[i].getArgumentTypes()[j] + "=" + args[j]);
                     if(args[j].equals(array[i].getArgumentTypes()[j])) {
                        found2 = true;
                     }
                     else {
                        found2 = false;
                        break;
                     }
                  }
                  if(found2) {
*/
                     return array[i];
                  //}
               }
            }
         }
         if(!cls.getClassName().equals("java.lang.Object")) {
            return get_method(cls.getSuperclassName(),m,args);
         }
      }

      return null;
   }

   public void print_fields(Field array2[]) {
      for(int i = 0; i < array2.length; i++) {
         if(array2[i].isStatic()) {
            String name = array2[i].getName();
            String type = to_class_type(array2[i].getType().toString());
            fout.println(".field " + name);
            fout.println(".access public");
            fout.println(".modifyers static");
            fout.println(".type " + type);
            fout.println();
            fout.flush();
         }
         else {
            String name = array2[i].getName();
            String type = to_class_type(array2[i].getType().toString());
            fout.println(".field " + name);
            fout.println(".access public");
            fout.println(".modifyers");
            fout.println(".type " + type);
            fout.println();
            fout.flush();
         }
      }
   }

   public void print_start_method(Method method, int maxStack) {
      String name = method.getName();
      fout.println(".method " + name);
      fout.println(".maxStack " + maxStack);
      fout.println(".access public");
      if(method.isStatic() && method.isNative()) {
         fout.println(".modifyers static native");
      }
      else if(method.isStatic()) {
         fout.println(".modifyers static");
      }
      else {
         fout.println(".modifyers");
      }
      fout.println(".signature " + method.getSignature());
      fout.print(".args ");
      Type[] args2 = Type.getArgumentTypes(method.getSignature());
      String str = "";
      for(int ii = 0; ii < args2.length; ii++) {
         if(str.length() > 0) {
            str += " ";
         }
         str += "arg" + ii;
      }
      fout.println(str);
      fout.println(".data");
      fout.println(".code");
      fout.println(".end");
      fout.println();
   }

   public void print_codes(Instruction instruction) {
      String temp_args;
      if(instruction.getName().startsWith("if")) {
         BranchInstruction b = (BranchInstruction)instruction;
         temp_args = "L" + (b.getTarget().getPosition());
         fout.println(b.getName() + " " + temp_args);
      }
      else if(instruction.getName().indexOf("iload_") == 0) {
         ILOAD il = (ILOAD)instruction;
         String n = instruction.getName().substring(6);
         fout.println("iload_" + n);
      }
      else if((instruction.getName()).indexOf("load") != -1) {
         LoadInstruction li = (LoadInstruction)instruction;
         if(li.getIndex() >= 0 && li.getIndex() <= 5) {
            fout.println(instruction.getName());
         }
         else {
            fout.println(instruction.getName() + " temp"+li.getIndex());
         }
      }
      else if(instruction.getName().startsWith("astore_")) {
         StoreInstruction si = (StoreInstruction)instruction;
         fout.println(instruction.getName());
      }
      else if(instruction.getName().startsWith("istore_")) {
         StoreInstruction si = (StoreInstruction)instruction;
         fout.println(instruction.getName());
      }
      else if(instruction.getName().startsWith("fstore_")) {
         StoreInstruction si = (StoreInstruction)instruction;
         fout.println(instruction.getName());
      }
      else if((instruction.getName()).indexOf("lstore_") != -1) {
         LSTORE si = (LSTORE)instruction;
         fout.println(si.getName());
      }
      else if((instruction.getName()).indexOf("dstore_") != -1) {
         DSTORE di = (DSTORE)instruction;
         fout.println(di.getName());
      }
      else if((instruction.getName()).indexOf("store") != -1) {
         StoreInstruction si = (StoreInstruction)instruction;
         if(si.getIndex() > 5) {
            fout.println(instruction.getName() + " temp"+si.getIndex());
         }
         else {
            fout.println(instruction.getName() + "_"+si.getIndex());
         }
      }
      else if(instruction.getName().equals("ldc") || instruction.getName().equals("ldc2_w")) {
         LDC ldc = (LDC)instruction;
         int index1 = ldc.getIndex();
         Constant c = cp.getConstant(index1);
         String temp = cp.constantToString(c);
         String arg = ldc.getType(gcp).toString();
         if(arg.equals("double")) {
            fout.println(instruction.getName() + "_double " + temp);
         }
         else if(arg.equals("float")) {
            fout.println(instruction.getName() + "_float " + temp);
         }
         else if(arg.equals("long")) {
            fout.println(instruction.getName() + "_long " + temp);
         }
         else if(arg.equals("int")) {
            fout.println(instruction.getName() + "_int " + temp);
         }
         else {
            if(temp.length() > 0) {
               if(temp.charAt(0) == '\"') {
                  fout.println(instruction.getName() + " " + (temp));
               }
               else {
                  fout.println(instruction.getName() + " " + (temp));
               }
            }
            else {
               fout.println(instruction.getName());
            }
         }
      }
      else {
         fout.println(instruction.getName());
      }
   }

   public void print_class_start(String the_class_name, JavaClass cls, String _package) {
      fout.println(".class "+the_class_name);
      fout.println(".access public");
      fout.println(".modifyers");
      fout.println(".extends " + cls.getSuperclassName());
      String impl = "";
      try {
         JavaClass array[] = cls.getAllInterfaces();
         if(array != null) {
            for(int i = 0; i < array.length; i++) {
               if(i != 0)
                  impl += ", ";
               impl += array[i].getClassName();
            }
         }
         fout.println(".implements " + impl);
      }
      catch(Exception ex) {
         ex.printStackTrace(System.err);
         System.exit(1);
      }
      fout.println(".package " + _package);
      fout.println();
   }

   public MethodGen print_method(Code code_obj, JavaClass cls, Method method, int maxParam0) {
      LocalVariableTable tbl = code_obj.getLocalVariableTable();
      String name = method.getName();
      int maxStack = 0;
      String temp1 = "temp1";
      String temp2 = "temp2";
      String temp3 = "temp3";

      fout.println(".method " + name);
      gcp = new ConstantPoolGen(cp);
      MethodGen mg = new MethodGen(method, cls.getClassName(), gcp);
      maxStack = mg.getMaxLocals();
      //maxStack = mg.getMaxStack();
      //if(tbl != null) {
         //maxStack = tbl.getTableLength();
      //}
      String type_signature1 = method.getSignature();
      String type_signature2 = to_type_signature(method.getSignature());
      int maxParam = count_param(method.getSignature());

      fout.println(".maxStack " + maxStack);
      fout.println(".access public");
      if(method.isStatic()) {
         fout.println(".modifyers static");
      }
      else {
         fout.println(".modifyers");
      }
      fout.println(".signature " + method.getSignature());
      fout.print(".args ");
      Type[] args2 = Type.getArgumentTypes(method.getSignature());
      String str = "";
      for(int ii = 0; ii < args2.length; ii++) {
         if(str.length() > 0) {
            str += " ";
         }
         str += "arg" + ii;
      }
      fout.println(str);
      fout.println(".data");

      String sig = "";
      sig = type_signature1;
      sig = to_type_signature(sig);
      String tt0 = method.getReturnType().toString();
      String mod = "";

      int ii = 0;
      int index = 1;
      Hashtable hash = new Hashtable();
      if(tbl != null) 
      for(int k = 0; k < tbl.getTableLength(); k++) {
         if(tbl.getLocalVariable(k) == null)
            continue;
         if(tbl.getLocalVariable(k).getName().equals("this"))
            continue;
         if(hash.get(tbl.getLocalVariable(k).getName()) != null) {
            continue;
         }
         hash.put(tbl.getLocalVariable(k).getName(), new Object());
         //fout.println("\tint " + tbl.getLocalVariable(k).getName());
         if(k == 1)
            temp1 = tbl.getLocalVariable(k).getName();
         else if(k == 2)
            temp2 = tbl.getLocalVariable(k).getName();
         else if(k == 3)
            temp3 = tbl.getLocalVariable(k).getName();
      }
      
      if(tbl != null)
      while((tbl.getTableLength() + ii) < maxStack) {
         fout.println("\tint temp");
         ii++;
         index++;
      }
      ii = 1;
      maxParam += maxParam0;
// MAX STACK
      maxStack -= maxParam;

      LocalVariableTable table2 = mg.getLocalVariableTable(mg.getConstantPool());

      LocalVariable[] table = table2.getLocalVariableTable();

      while(ii < maxStack) {
         fout.println("\tint temp" + ((maxStack + maxParam) - ii));
         ii++;
      }

      while(ii < (maxStack + maxParam)) {
         fout.println("\tint temp" + ((maxStack + maxParam) - ii));
         ii++;
      }
      fout.println("\tint temp0");
      fout.println("\tint global_temp1");
      fout.println("\tint global_temp2");

      fout.println(".code");
      int count = 0;
      Instruction instruction;
      Hashtable found = new Hashtable();
      for(InstructionHandle ih = mg.getInstructionList().getStart();
            ih != null; ih = ih.getNext()) {
         instruction = ih.getInstruction();
         if(instruction instanceof BranchInstruction) {
            count = ((BranchInstruction)instruction).getTarget().getPosition();
            found.put("L"+count, new Boolean(true));
         }
      }
      return mg;
   }

   public void java_2_asm(String args[]) throws Exception {
      int maxParam = 0;
      int maxParam0 = 0;
      Type tt[] = null;

      String temp_name = args[0];

      temp_name = temp_name.replace(".", "\\");
      temp_name = temp_name.replace("\\class", ".class");

      ClassParser parser = null;
      JavaClass cls = null;

      try {
         parser = new ClassParser(temp_name);
         cls = parser.parse();
      }
      catch(Exception ex) {
         parser = new ClassParser(rt + temp_name);
         cls = parser.parse();
      }

      cp = cls.getConstantPool();

      String temp_class_name = class_name;

      class_name = cls.getClassName();

      _package = cls.getPackageName();

      Method array[] = cls.getMethods();
      Field array2[] = cls.getFields();

      JavaClass interface_array[] = cls.getAllInterfaces();

      String name_temp = class_name.substring(index0+1);

      String cls_name = name_temp;

      JavaClass super_array[] = cls.getSuperClasses();

      print_class_start(the_class_name,cls,_package);

      int maxStack = 0;
      String temp1 = "temp1";
      String temp2 = "temp2";
      String temp3 = "temp3";

      String name,type;

      print_fields(array2);
      for(int i = 0; i < array.length; i++) {
         Code code_obj = array[i].getCode();
         if(code_obj == null) {
            print_start_method(array[i],maxStack);
            continue;
         }
         MethodGen mg = print_method(code_obj, cls, array[i], maxParam0);
         int count = 0;
         for(InstructionHandle ih = mg.getInstructionList().getStart();
             ih != null; ih = ih.getNext()) {
            Instruction instruction = ih.getInstruction();
//System.out.println(instruction.getName());
            MyCode code = code_map.get(instruction.getName());
            if(code != null) {
               fout.print("L" + ih.getPosition() + ":\t");
               code.run(instruction);
               count += instruction.getLength();
               continue;
            }
            fout.print("L" + ih.getPosition() + ":\t");
            String temp_args = "";
            print_codes(instruction);
            count += instruction.getLength();
         }
         fout.println(".end");
         fout.println();
      }
      fout.println();
   }
}


