/*
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html.
 * 
 * This file is a derivative of code released under the terms listed below.  
 *
 * dexlib2 update: Julian Dolby (dolby@us.ibm.com)
 * 
 */
/*
 *
 * Copyright (c) 2009-2012,
 *
 *  Jonathan Bardin     <astrosus@gmail.com>
 *  Steve Suh           <suhsteve@gmail.com>
 *
 * 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 names of the contributors may not be used to endorse or promote
 * products derived from this software without specific prior written
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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.
 *
 *
 */

package com.ibm.wala.dalvik.classLoader;

import static org.jf.dexlib2.AccessFlags.ABSTRACT;
import static org.jf.dexlib2.AccessFlags.BRIDGE;
import static org.jf.dexlib2.AccessFlags.DECLARED_SYNCHRONIZED;
import static org.jf.dexlib2.AccessFlags.FINAL;
import static org.jf.dexlib2.AccessFlags.NATIVE;
import static org.jf.dexlib2.AccessFlags.PRIVATE;
import static org.jf.dexlib2.AccessFlags.PROTECTED;
import static org.jf.dexlib2.AccessFlags.PUBLIC;
import static org.jf.dexlib2.AccessFlags.STATIC;
import static org.jf.dexlib2.AccessFlags.VOLATILE;
import static org.jf.dexlib2.AccessFlags.SYNTHETIC;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.analysis.ClassPath;
import org.jf.dexlib2.analysis.ClassPathResolver;
import org.jf.dexlib2.analysis.MethodAnalyzer;
import org.jf.dexlib2.iface.AnnotationElement;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.iface.instruction.SwitchPayload;
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction;
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
import org.jf.dexlib2.iface.instruction.formats.Instruction10t;
import org.jf.dexlib2.iface.instruction.formats.Instruction11n;
import org.jf.dexlib2.iface.instruction.formats.Instruction11x;
import org.jf.dexlib2.iface.instruction.formats.Instruction12x;
import org.jf.dexlib2.iface.instruction.formats.Instruction20t;
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
import org.jf.dexlib2.iface.instruction.formats.Instruction21ih;
import org.jf.dexlib2.iface.instruction.formats.Instruction21lh;
import org.jf.dexlib2.iface.instruction.formats.Instruction21s;
import org.jf.dexlib2.iface.instruction.formats.Instruction21t;
import org.jf.dexlib2.iface.instruction.formats.Instruction22b;
import org.jf.dexlib2.iface.instruction.formats.Instruction22c;
import org.jf.dexlib2.iface.instruction.formats.Instruction22s;
import org.jf.dexlib2.iface.instruction.formats.Instruction22t;
import org.jf.dexlib2.iface.instruction.formats.Instruction22x;
import org.jf.dexlib2.iface.instruction.formats.Instruction23x;
import org.jf.dexlib2.iface.instruction.formats.Instruction30t;
import org.jf.dexlib2.iface.instruction.formats.Instruction31c;
import org.jf.dexlib2.iface.instruction.formats.Instruction31i;
import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
import org.jf.dexlib2.iface.instruction.formats.Instruction32x;
import org.jf.dexlib2.iface.instruction.formats.Instruction35c;
import org.jf.dexlib2.iface.instruction.formats.Instruction3rc;
import org.jf.dexlib2.iface.instruction.formats.Instruction51l;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.iface.value.EncodedValue;
import org.jf.dexlib2.iface.value.TypeEncodedValue;

import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IBytecodeMethod;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.dalvik.dex.instructions.ArrayFill;
import com.ibm.wala.dalvik.dex.instructions.ArrayGet;
import com.ibm.wala.dalvik.dex.instructions.ArrayGet.Type;
import com.ibm.wala.dalvik.dex.instructions.ArrayLength;
import com.ibm.wala.dalvik.dex.instructions.ArrayPut;
import com.ibm.wala.dalvik.dex.instructions.BinaryLiteralOperation;
import com.ibm.wala.dalvik.dex.instructions.BinaryOperation;
import com.ibm.wala.dalvik.dex.instructions.Branch;
import com.ibm.wala.dalvik.dex.instructions.CheckCast;
import com.ibm.wala.dalvik.dex.instructions.Constant;
import com.ibm.wala.dalvik.dex.instructions.GetField;
import com.ibm.wala.dalvik.dex.instructions.Goto;
import com.ibm.wala.dalvik.dex.instructions.InstanceOf;
import com.ibm.wala.dalvik.dex.instructions.Instruction;
import com.ibm.wala.dalvik.dex.instructions.Invoke;
import com.ibm.wala.dalvik.dex.instructions.Monitor;
import com.ibm.wala.dalvik.dex.instructions.New;
import com.ibm.wala.dalvik.dex.instructions.NewArray;
import com.ibm.wala.dalvik.dex.instructions.NewArrayFilled;
import com.ibm.wala.dalvik.dex.instructions.PackedSwitchPad;
import com.ibm.wala.dalvik.dex.instructions.PutField;
import com.ibm.wala.dalvik.dex.instructions.Return;
import com.ibm.wala.dalvik.dex.instructions.SparseSwitchPad;
import com.ibm.wala.dalvik.dex.instructions.Switch;
import com.ibm.wala.dalvik.dex.instructions.Throw;
import com.ibm.wala.dalvik.dex.instructions.UnaryOperation;
import com.ibm.wala.dalvik.dex.instructions.UnaryOperation.OpID;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.shrikeBT.ExceptionHandler;
import com.ibm.wala.shrikeBT.IndirectionData;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.types.annotations.Annotation;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.util.strings.ImmutableByteArray;


/**
 * A wrapper around a EncodedMethod object (from dexlib) that represents a method.
 */
public class DexIMethod implements IBytecodeMethod<Instruction> {

	/**
	 * The EncodedMethod object for which this DexIMethod is a wrapper.
	 */
	private final Method eMethod;

	/**
	 * The declaring class for this method.
	 */
	protected final DexIClass myClass;

	/**
	 * canonical MethodReference corresponding to this method,
	 * construct in the getReference method.
	 */
	private MethodReference methodReference;

	/**
	 * name of the return type for this method,
	 * construct in the get return type method.
	 */
	private TypeReference typeReference;

	private ExceptionHandler[][] handlers;
	
	protected InstructionArray instructions;



	private static int totalInsts = 0;

	public DexIMethod(Method encodedMethod, DexIClass klass) {
		eMethod = encodedMethod;
		myClass = klass;
	}

	public static int getTotalInsts() {
		return totalInsts;
	}

	//------------------------------------------
	// Specific methods
	//------------------------------------------

	/**
	 * @return the EncodedMethod object for which this DexIMethod is a wrapper.
	 */
	public Method toEncodedMethod() {
		return eMethod;
	}


	//-------------------------------------------
	// IMethod methods
	//-------------------------------------------

	@Override
	public TypeReference[] getDeclaredExceptions()
			throws UnsupportedOperationException {
/** BEGIN Custom change: Variable Names in synth. methods */
        if (myClass.getClassDefItem().getAnnotations() == null) {
            return null;
        }
        ArrayList<String> strings = new ArrayList<>();
        Set<? extends org.jf.dexlib2.iface.Annotation> annotationSet = eMethod.getAnnotations();
/** END Custom change: Variable Names in synth. methods */

        if (annotationSet != null) {
			for (org.jf.dexlib2.iface.Annotation annotationItem: annotationSet)
			{
				if (annotationItem.getType().contentEquals("Ldalvik/annotation/Throws;")) {
					for (AnnotationElement e : annotationItem.getElements()) {
						for (EncodedValue v : ((ArrayEncodedValue)e.getValue()).getValue()) {
							String tname = ((TypeEncodedValue)v).getValue();
							if (tname.endsWith(";"))
								tname = tname.substring(0,tname.length()-1);
							strings.add(tname);
						}
					}
				}
			}
		}

		if (strings.size() == 0)
			return null;

		ClassLoaderReference loader = getDeclaringClass().getClassLoader().getReference();

		TypeReference[] result = new TypeReference[strings.size()];
		for (int i = 0; i < result.length; i++) {
			result[i] = TypeReference.findOrCreate(loader, TypeName.findOrCreate(ImmutableByteArray.make(strings.get(i))));
		}
		return result;
	}


	@Override
	public String getLocalVariableName(int bcIndex, int localNumber) {
		throw new UnsupportedOperationException("getLocalVariableName not implemented");
	}

	/**
	 * XXX not fully about the + 2.
	 * @return the RegisterCount + 2 to make some room for the return and exception register
	 * @see com.ibm.wala.classLoader.ShrikeCTMethod#getMaxLocals()
	 */
	public int getMaxLocals() {
		return eMethod.getImplementation().getRegisterCount() + 2;
	}

	public int getReturnReg() {
		return eMethod.getImplementation().getRegisterCount();
	}

	public int getExceptionReg() {
		return eMethod.getImplementation().getRegisterCount()+1;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#getMaxStackHeight()
	 */
	public int getMaxStackHeight() {
		throw new UnsupportedOperationException("Dex Methods does not use a stack");
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#getDescriptor()
	 */
	@Override
	public Descriptor getDescriptor() {
		return getReference().getDescriptor();
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#getNumberOfParameters()
	 */
	@Override
	public int getNumberOfParameters() {
		final int number;


		if (isStatic() || isClinit()) {
			number = getReference().getNumberOfParameters();
		} else {
			number = getReference().getNumberOfParameters() + 1;
		}

		return number;
	}

	public int getNumberOfParameterRegisters() {
		int number = isStatic() || isClinit() ? 0 : 1;

		for(int i = 0; i < getReference().getNumberOfParameters(); i++) {
			TypeReference ref = getReference().getParameterType(i);
			number += ref.equals(TypeReference.Double) || ref.equals(TypeReference.Long) ? 2 : 1;
		}
		
		return number;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#getParameterType(int)
	 */
	@Override
	public TypeReference getParameterType(int index) {
		if (!isStatic()) {
			if (index == 0) {
				return myClass.getReference();
			} else {
				return getReference().getParameterType(index - 1);
			}
		} else {
			return getReference().getParameterType(index);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#getReference()
	 */
	@Override
	public MethodReference getReference() {
		//Compute the method reference from the MethodIdItem
		if (methodReference == null) {
			// Set method name
			Atom name = Atom.findOrCreateUnicodeAtom(eMethod.getName());

			//            // Set the descriptor
			//            Descriptor descriptor = Descriptor.findOrCreateUTF8(eMethod.method.getPrototype().getPrototypeString());
			//            methodReference = MethodReference.findOrCreate(myClass.getReference(),name, descriptor);

			Descriptor D = Descriptor.findOrCreate(myClass.getClassLoader().getLanguage(), ImmutableByteArray.make(DexUtil.getSignature(eMethod)));
			methodReference = MethodReference.findOrCreate(myClass.getReference(), name, D);
		}

		return methodReference;
	}


	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#getReturnType()
	 */
	@Override
	public TypeReference getReturnType() {
		//compute the typeReference from the MethodIdItem
		if (typeReference == null) {
			typeReference = getReference().getReturnType();
		}

		return typeReference;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#getSelector()
	 */
	@Override
	public Selector getSelector() {
		return getReference().getSelector();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.ibm.wala.classLoader.IMethod#getSignature()
	 */
	@Override
	public String getSignature() {
		return getReference().getSignature();
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#hasExceptionHandler()
	 */
	@Override
	public boolean hasExceptionHandler() {
		List<? extends TryBlock<? extends org.jf.dexlib2.iface.ExceptionHandler>> tries = eMethod.getImplementation().getTryBlocks();
		return tries==null?false:tries.size() > 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable()
	 */
	@Override
	public boolean hasLocalVariableTable() {
		throw new UnsupportedOperationException("DexIMethod: hasLocalVariableTable() not yet implemented");
		//TODO Compute the local variable name from the DebugInfo Item
		//eMethod.codeItem.getDebugInfo()
		//      return false;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isAbstract()
	 */
	@Override
	public boolean isAbstract() {
		return (eMethod.getAccessFlags() & ABSTRACT.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isClinit()
	 */
	@Override
	public boolean isClinit() {
		return eMethod.getName().equals(MethodReference.clinitName.toString());
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isFinal()
	 */
	@Override
	public boolean isFinal() {
		return (eMethod.getAccessFlags() & FINAL.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isInit()
	 */
	@Override
	public boolean isInit() {
		return eMethod.getName().equals(MethodReference.initAtom.toString());
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isNative()
	 */
	@Override
	public boolean isNative() {
		return (eMethod.getAccessFlags() & NATIVE.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isBridge()
	 */
	@Override
	public boolean isBridge() {
		return (eMethod.getAccessFlags() & BRIDGE.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isPrivate()
	 */
	@Override
	public boolean isPrivate() {
		return (eMethod.getAccessFlags() & PRIVATE.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isProtected()
	 */
	@Override
	public boolean isProtected() {
		return (eMethod.getAccessFlags() & PROTECTED.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.ibm.wala.classLoader.IMethod#isPublic()
	 */
	@Override
	public boolean isPublic() {
		return (eMethod.getAccessFlags() & PUBLIC.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isSynchronized()
	 */
	@Override
	public boolean isSynchronized() {
		return (eMethod.getAccessFlags() & DECLARED_SYNCHRONIZED.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMethod#isWalaSynthetic()
	 */
	@Override
	public boolean isWalaSynthetic() {
		return false;
	}

    /*
     * (non-Javadoc)
     * @see com.ibm.wala.classLoader.IMethod#isSynthetic()
     */
    @Override
    public boolean isSynthetic() { return (eMethod.getAccessFlags() & SYNTHETIC.getValue()) != 0; }

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMember#isStatic()
	 */
	@Override
	public boolean isStatic() {
		return (eMethod.getAccessFlags() & STATIC.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMember#isVolatile()
	 */
	public boolean isVolatile() {
		return (eMethod.getAccessFlags() & VOLATILE.getValue()) != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see com.ibm.wala.classLoader.IMember#getDeclaringClass()
	 */
	@Override
	public IClass getDeclaringClass() {
		return myClass;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.ibm.wala.ipa.cha.IClassHierarchyDweller#getClassHierarchy()
	 */
	@Override
	public IClassHierarchy getClassHierarchy() {
		return myClass.getClassHierarchy();
	}

	@Override
	public Atom getName() {
		return getReference().getName();
	}

	@Override
	public int getLineNumber(int bcIndex) {
		return getInstructionIndex(bcIndex);
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return getReference().toString();
	}

	@Override
	public boolean equals(Object obj) {
		// instanceof is OK because this class is final.
		// if (this.getClass().equals(obj.getClass())) {
		if (obj instanceof DexIMethod) {
			DexIMethod that = (DexIMethod) obj;
			return (getDeclaringClass().equals(that.getDeclaringClass()) && getReference().equals(that.getReference()));
		} else {
			return false;
		}
	}

	@Override
	public int hashCode() {
		return 9661 * getReference().hashCode();
	}



	//-------------------------------------------
	// IByteCodeMethod methods
	// (required to build the ShrikeCFG)
	//-------------------------------------------


	@Override
	public int getBytecodeIndex(int i) {
		// TODO Auto-generated method stub
		//      System.out.println("DexIMethod: getBytecodeIndex() possibly not implemented correctly");
		//      Integer.valueOf(eMethod.codeItem.getInstructions()[i].opcode.value);
		//      return i;
		return getAddressFromIndex(i);
		//      return -1;
	}


	@Override
	public ExceptionHandler[][] getHandlers() {

		if (handlers != null)
			return handlers;

		//ExceptionHandler[][] handlers = new ExceptionHandler[eMethod.codeItem.getInstructions().length][];

		List<? extends TryBlock<? extends org.jf.dexlib2.iface.ExceptionHandler>> tryBlocks = eMethod.getImplementation().getTryBlocks();

		//
		//      if (tries == null){
		//          return new ExceptionHandler[eMethod.codeItem.getInstructions().length][];
		//      }
		//      ExceptionHandler[][] handlers = new ExceptionHandler[tries.length][];
		//      for (int i = 0; i < tries.length; i++) {
		//          EncodedTypeAddrPair[] etaps = tries[i].encodedCatchHandler.handlers;
		//          handlers[i] = new ExceptionHandler[etaps.length];
		//          for (int j = 0; j < etaps.length; j++) {
		//              EncodedTypeAddrPair etap = etaps[j];
		//              handlers[i][j] = new ExceptionHandler(etap.getHandlerAddress(), etap.exceptionType.getTypeDescriptor());
		//          }
		//      }

		this.handlers = new ExceptionHandler[instructions().size()][];
		if (tryBlocks == null){
			//          return new ExceptionHandler[instructions.size()][];
			return handlers;
		}

		ArrayList<ArrayList<ExceptionHandler>> temp_array = new ArrayList<>();
		for (int i = 0; i < instructions().size(); i++) {
			temp_array.add(new ArrayList<ExceptionHandler>());
		}

		for (TryBlock<? extends org.jf.dexlib2.iface.ExceptionHandler> tryItem: tryBlocks) {
			int startAddress = tryItem.getStartCodeAddress();
			int endAddress = tryItem.getStartCodeAddress() + tryItem.getCodeUnitCount();
			/**
			 * The end address points to the address immediately after the end of the last
			 * instruction that the try block covers. We want the .catch directive and end_try
			 * label to be associated with the last covered instruction, so we need to get
			 * the address for that instruction
			 */


			int startInst = getInstructionIndex(startAddress);
			int endInst;
			/**
			 * The try block can extend to the last instruction in the method.  If this is the
			 * case then endAddress will be the address immediately following the last instruction.
			 * Check to make sure this is the case.
			 */
			if (endAddress > getAddressFromIndex(instructions().size()-1)) {
				endInst = instructions().size()-1;
				int endSize = 0;
				for(org.jf.dexlib2.iface.instruction.Instruction inst : eMethod.getImplementation().getInstructions()) {
					endSize = inst.getCodeUnits();
				}
				if (endAddress != (getAddressFromIndex(endInst) + endSize))
					throw new RuntimeException("Invalid code offset " + endAddress + " for the try block end address");
			}
			else {
				endInst = getInstructionIndex(endAddress) - 1;
			}

			for (int i = startInst; i <= endInst; i++) {
				//add the rest of the handlers
				for (org.jf.dexlib2.iface.ExceptionHandler etaps: tryItem.getExceptionHandlers()) {
					temp_array.get(i).add(new ExceptionHandler( getInstructionIndex(etaps.getHandlerCodeAddress()), etaps.getExceptionType() ));
				}
			}
		}


		for (int i = 0; i < instructions().size(); i++) {
			handlers[i] = temp_array.get(i).toArray(new ExceptionHandler[0]);
		
			/*
			System.out.println("i: " + i);
			for (int j = 0; j < handlers[i].length; j++) {
				System.out.println("\t j: " + j);
				System.out.println("\t\t Handler: " +  handlers[i][j].getHandler());
				System.out.println("\t\t Catch Class: " + handlers[i][j].getCatchClass());
			}
			*/
		}

		return handlers;
	}



	@Override
	public Instruction[] getInstructions() {
		if (instructions == null)
			parseBytecode();

		return instructions.toArray(new Instruction[0]);
	}

	private boolean odexMethod() {
		for(org.jf.dexlib2.iface.instruction.Instruction inst : eMethod.getImplementation().getInstructions()) {
			if (inst.getOpcode().odexOnly()) {
				return true;
			}
		}
		
		return false;
	}

	Iterable<? extends org.jf.dexlib2.iface.instruction.Instruction> deodex() {
		try {
			DexFileModule m = myClass.getContainer();

			ClassPathResolver path = 
					new ClassPathResolver(Collections.singletonList(m.getFile().getParent() + '/'),
							Collections.<String>emptyList(),
							m.getDexFile());

			ClassPath cp = new ClassPath(path.getResolvedClassProviders(), false, m.getDexFile().getOpcodes().artVersion);

			MethodAnalyzer analyzer = new MethodAnalyzer(cp, eMethod, null, false);

			return analyzer.getInstructions();
		} catch (Exception e) {
			assert false : e;
		    return eMethod.getImplementation().getInstructions();
		}
	}
	
	protected void parseBytecode() {

		Iterable<? extends org.jf.dexlib2.iface.instruction.Instruction> instrucs = 
			odexMethod()?
			    deodex():
				eMethod.getImplementation().getInstructions();

		//      for (org.jfmethod.getInstructionIndex(.dexlib.Code.Instruction inst: instrucs)
		//      {
		//          switch (inst.getFormat())
		//          {
		//
		//          case Format10t:
		//              instructions.add(new IInstruction10t((Instruction10t)inst, this));
		//              break;
		//          case Format10x:
		//              instructions.add(new IInstruction10x((Instruction10x)inst, this));
		//              break;
		//          case Format11n:
		//              instructions.add(new IInstruction11n((Instruction11n)inst, this));
		//              break;
		//          case Format11x:
		//              instructions.add(new IInstruction11x((Instruction11x)inst, this));
		//              break;
		//          case Format12x:
		//              instructions.add(new IInstruction12x((Instruction12x)inst, this));
		//              break;
		//          case Format20t:
		//              instructions.add(new IInstruction20t((Instruction20t)inst, this));
		//              break;
		//          case Format21c:
		//              instructions.add(new IInstruction21c((Instruction21c)inst, this));
		//              break;
		//          case Format21h:
		//              instructions.add(new IInstruction21h((Instruction21h)inst, this));
		//              break;
		//          case Format21s:
		//              instructions.add(new IInstruction21s((Instruction21s)inst, this));
		//              break;
		//          case Format21t:
		//              instructions.add(new IInstruction21t((Instruction21t)inst, this));
		//              break;
		//          case Format22b:
		//              instructions.add(new IInstruction22b((Instruction22b)inst, this));
		//              break;
		//          case Format22c:
		//              instructions.add(new IInstruction22c((Instruction22c)inst, this));
		//              break;
		//          case Format22cs:
		//              instructions.add(new IInstruction22cs((Instruction22cs)inst, this));
		//              break;
		//          case Format22s:
		//              instructions.add(new IInstruction22s((Instruction22s)inst, this));
		//              break;
		//          case Format22t:
		//              instructions.add(new IInstruction22t((Instruction22t)inst, this));
		//              break;
		//          case Format22x:
		//              instructions.add(new IInstruction22x((Instruction22x)inst, this));
		//              break;
		//          case Format23x:
		//              instructions.add(new IInstruction23x((Instruction23x)inst, this));
		//              break;
		//          case Format30t:
		//              instructions.add(new IInstruction30t((Instruction30t)inst, this));
		//              break;
		//          case Format31c:
		//              instructions.add(new IInstruction31c((Instruction31c)inst, this));
		//              break;
		//          case Format31i:
		//              instructions.add(new IInstruction31i((Instruction31i)inst, this));
		//              break;
		//          case Format31t:
		//              instructions.add(new IInstruction31t((Instruction31t)inst, this));
		//              break;
		//          case Format32x:
		//              instructions.add(new IInstruction32x((Instruction32x)inst, this));
		//              break;
		//          case Format35c:
		//              instructions.add(new IInstruction35c((Instruction35c)inst, this));
		//              break;
		//          case Format35ms:
		//              instructions.add(new IInstruction35ms((Instruction35ms)inst, this));
		//              break;
		//          case Format35s:
		//              instructions.add(new IInstruction35s((Instruction35s)inst, this));
		//              break;
		//          case Format3rc:
		//              instructions.add(new IInstruction3rc((Instruction3rc)inst, this));
		//              break;
		//          case Format3rms:
		//              instructions.add(new IInstruction3rms((Instruction3rms)inst, this));
		//              break;
		//          case Format51l:
		//              instructions.add(new IInstruction51l((Instruction51l)inst, this));
		//              break;
		//          case ArrayData:
		//              instructions.add(new IArrayDataPseudoInstruction((ArrayDataPseudoInstruction)inst, this));
		//              break;
		//          case PackedSwitchData:
		//              instructions.add(new IPackedSwitchDataPseudoInstruction((PackedSwitchDataPseudoInstruction)inst, this));
		//              break;
		//          case SparseSwitchData:
		//              instructions.add(new ISparseSwitchDataPseudoInstruction((SparseSwitchDataPseudoInstruction)inst, this));
		//              break;
		//          case UnresolvedOdexInstruction:
		//              instructions.add(new IUnresolvedOdexInstruction((UnresolvedOdexInstruction)inst, this));
		//              break;
		//
		//          }
		//      }

		//if (eMethod.method.getMethodString().contentEquals("Lorg/xbill/DNS/Name;-><init>([B)V") && instrucs.length == 4)
		//  System.out.println("debug here");



		instructions = new InstructionArray();
		int instLoc = 0;
		int instCounter = -1;
		//int pc = 0;
		int currentCodeAddress = 0;
		for (org.jf.dexlib2.iface.instruction.Instruction inst: instrucs)
		{
			totalInsts++;
			instCounter++;
			//          instLoc = pc - instCounter;
			instLoc = currentCodeAddress;
			//pc += inst.getFormat().size;
			switch(inst.getOpcode())
			{
			case NOP:
			case ARRAY_PAYLOAD:
			case PACKED_SWITCH_PAYLOAD:
			case SPARSE_SWITCH_PAYLOAD:
				switch (inst.getOpcode().format)
				{
				case ArrayPayload:
				{
					for (int i = 0; i < instructions.size(); i++)
					{
						if (instructions.getFromId(i) instanceof ArrayFill)
							if (instLoc == (((ArrayFill)getInstructionFromIndex(i)).tableAddressOffset + getAddressFromIndex(i)))
							{
								((ArrayFill)getInstructionFromIndex(i)).setArrayDataTable((ArrayPayload)inst);



								//                              Iterator<ArrayElement> b = (((ArrayDataPseudoInstruction)inst).getElements());
								//                              while (b.hasNext())
									//                              {
								//                                  int ElementWidth = ((ArrayDataPseudoInstruction)inst).getElementWidth();
								//                                  byte[] temp_byte = new byte[ElementWidth];
								//
								//                                  ArrayElement t = (ArrayElement)b.next();
								//                                  for (int j = 0; j < ElementWidth; j++)
								//                                      temp_byte[j] = t.buffer[t.bufferIndex+(ElementWidth-1)-j];
								//
								//                                  ByteBuffer byte_buffer = ByteBuffer.wrap(temp_byte);
								//
								//                                  System.out.println("Index: " + t.bufferIndex + ", Width: " + t.elementWidth + ", Value: " +  byte_buffer.getChar());
								//                              }


								break;
							}
					}
					break;
				}
				case PackedSwitchPayload:
					for (int i = 0; i < instructions.size(); i++)
					{
						if (instructions.getFromId(i) instanceof Switch)
							if (instLoc == (((Switch)getInstructionFromIndex(i)).tableAddressOffset + getAddressFromIndex(i)))
							{
								((Switch)getInstructionFromIndex(i))
								   .setSwitchPad(new PackedSwitchPad(
										   (SwitchPayload)inst,
										   getAddressFromIndex(i+1) - getAddressFromIndex(i)));
								break;
							}
					}
					break;
				case SparseSwitchPayload:
				{
					for (int i = 0; i < instructions.size(); i++)
					{
						if (instructions.getFromId(i) instanceof Switch)
							if (instLoc == (((Switch)getInstructionFromIndex(i)).tableAddressOffset + getAddressFromIndex(i)))
							{
								((Switch)getInstructionFromIndex(i)).setSwitchPad(
										new SparseSwitchPad(
											(SwitchPayload)inst,
											getAddressFromIndex(i+1) - getAddressFromIndex(i)));
								break;
							}
					}
					//                  System.out.println("Targets: " + ((SparseSwitchDataPseudoInstruction)inst).getTargetCount());
					//                  Iterator<SparseSwitchTarget> i = (((SparseSwitchDataPseudoInstruction)inst).iterateKeysAndTargets());
					//                  while (i.hasNext())
						//                  {
						//                      SparseSwitchTarget t = (SparseSwitchTarget)i.next();
						//                      System.out.println("Key: " + t.key + ", TargetAddressOffset: " + t.targetAddressOffset);
					//                  }
					break;
				}
				default:
					class NOPInstruction extends Instruction {
						private NOPInstruction(int pc, Opcode op, DexIMethod method) {
							super(pc, op, method);
						}

						@Override
						public void visit(Visitor visitor) {
							// no op
						} 
					}
					
					instructions.add(new NOPInstruction(currentCodeAddress, Opcode.NOP, this));
					break;
				}
				break;
			case MOVE:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_FROM16:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE, ((Instruction22x)inst).getRegisterA(),
						((Instruction22x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_16:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE, ((Instruction32x)inst).getRegisterA(),
						((Instruction32x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_WIDE:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE_WIDE,
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_WIDE_FROM16:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE_WIDE,
						((Instruction22x)inst).getRegisterA(), ((Instruction22x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_WIDE_16:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE_WIDE,
						((Instruction32x)inst).getRegisterA(), ((Instruction32x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_OBJECT:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_OBJECT_FROM16:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE, ((Instruction22x)inst).getRegisterA(),
						((Instruction22x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_OBJECT_16:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE, ((Instruction32x)inst).getRegisterA(),
						((Instruction32x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MOVE_RESULT:
				//register b set as return register, -1;
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE, ((Instruction11x)inst).getRegisterA(), getReturnReg(), inst.getOpcode(), this));
				break;
			case MOVE_RESULT_WIDE:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE_WIDE,
						((Instruction11x)inst).getRegisterA(), getReturnReg(), inst.getOpcode(), this));
				break;
			case MOVE_RESULT_OBJECT:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE, ((Instruction11x)inst).getRegisterA(),
						getReturnReg(), inst.getOpcode(), this));
				break;
			case MOVE_EXCEPTION:
				instructions.add(new UnaryOperation(instLoc,
						UnaryOperation.OpID.MOVE_EXCEPTION, ((Instruction11x)inst).getRegisterA(),
						getExceptionReg(), inst.getOpcode(), this));
				break;
			case RETURN_VOID:
			case RETURN_VOID_NO_BARRIER:
				instructions.add(new Return.ReturnVoid(instLoc, inst.getOpcode(), this));
				break;
			case RETURN:
				//I think only primitives call return, and objects call return-object
				instructions.add(new Return.ReturnSingle(instLoc,
						((Instruction11x)inst).getRegisterA(), true, inst.getOpcode(), this));
				break;
			case RETURN_WIDE:
				//+1 to second parameter okay?
				instructions.add(new Return.ReturnDouble(instLoc,
						((Instruction11x)inst).getRegisterA(), ((Instruction11x)inst).getRegisterA()+1, inst.getOpcode(), this));
				break;
			case RETURN_OBJECT:
				instructions.add(new Return.ReturnSingle(instLoc,
						((Instruction11x)inst).getRegisterA(), false, inst.getOpcode(), this));
				break;
			case CONST_4: {
				instructions.add(new Constant.IntConstant(instLoc,
						((Instruction11n)inst).getNarrowLiteral(),((Instruction11n)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			}
			case CONST_16:
				instructions.add(new Constant.IntConstant(instLoc,
						((Instruction21s)inst).getNarrowLiteral(), ((Instruction21s)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST:
				instructions.add(new Constant.IntConstant(instLoc,
						((Instruction31i)inst).getNarrowLiteral(), ((Instruction31i)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST_HIGH16:
				instructions.add(new Constant.IntConstant(instLoc,
						((Instruction21ih)inst).getHatLiteral() << 16, ((Instruction21ih)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST_WIDE_16:
				instructions.add(new Constant.LongConstant(instLoc,
						((Instruction21s)inst).getWideLiteral(), ((Instruction21s)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST_WIDE_32:
				instructions.add(new Constant.LongConstant(instLoc,
						((Instruction31i)inst).getWideLiteral(), ((Instruction31i)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST_WIDE:
				instructions.add(new Constant.LongConstant(instLoc,
						((Instruction51l)inst).getWideLiteral(), ((Instruction51l)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST_WIDE_HIGH16:
				instructions.add(new Constant.LongConstant(instLoc,
						((Instruction21lh)inst).getWideLiteral() << 16, ((Instruction21lh)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST_STRING:

				instructions.add(new Constant.StringConstant(instLoc,
						((StringReference)((Instruction21c)inst).getReference()).getString(),
						((Instruction21c)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST_STRING_JUMBO:
				instructions.add(new Constant.StringConstant(instLoc,
						((StringReference)((Instruction31c)inst).getReference()).getString(),
						((Instruction31c)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CONST_CLASS: {
				String cname = ((org.jf.dexlib2.iface.reference.TypeReference)((Instruction21c)inst).getReference()).getType();
				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);
				
				//IClass ic = this.myClass.loader.lookupClass(TypeName.findOrCreate(cname));
				TypeReference typeRef = TypeReference.findOrCreate(myClass.getClassLoader().getReference(), cname);
				
				instructions.add(new Constant.ClassConstant(instLoc,
						typeRef, ((Instruction21c)inst).getRegisterA(), inst.getOpcode(), this));
				//logger.debug("myClass found name: " + this.myClass.loader.lookupClass(TypeName.findOrCreate(cname)).toString());
				break;
			}
			case MONITOR_ENTER:
				instructions.add(new Monitor(instLoc, true, ((Instruction11x)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case MONITOR_EXIT:
				instructions.add(new Monitor(instLoc, false, ((Instruction11x)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case CHECK_CAST: {
				String cname = ((org.jf.dexlib2.iface.reference.TypeReference)((Instruction21c)inst).getReference()).getType();
				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);


				//retrieving type reference correctly?
				instructions.add(new CheckCast(instLoc,
						TypeReference.findOrCreate(myClass.getClassLoader().getReference(), cname),
						((Instruction21c)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			}
			case INSTANCE_OF: {
				String cname = ((org.jf.dexlib2.iface.reference.TypeReference)((Instruction22c)inst).getReference()).getType();
				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);
				instructions.add(new InstanceOf(instLoc,
						((Instruction22c)inst).getRegisterA(),
						TypeReference.findOrCreate(myClass.getClassLoader().getReference(),
								cname),
								((Instruction22c)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			}
			case ARRAY_LENGTH:
				instructions.add(new ArrayLength(instLoc,
						((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case NEW_INSTANCE: {
				//newsitereference use instLoc or pc?
				String cname = ((org.jf.dexlib2.iface.reference.TypeReference)((Instruction21c)inst).getReference()).getType();
				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);

				instructions.add(new New(instLoc,
						((Instruction21c)inst).getRegisterA(),
						NewSiteReference.make(instLoc, TypeReference.findOrCreate(myClass.getClassLoader().getReference(),
								cname)), inst.getOpcode(), this));
				break;
			}
			case NEW_ARRAY:
			{
				int[] params = new int[1];
				params[0] = ((Instruction22c)inst).getRegisterB();
				//              MyLogger.log(LogLevel.INFO, "Type: " +((TypeIdItem)((Instruction22c)inst).getReferencedItem()).getTypeDescriptor());

				String cname = ((org.jf.dexlib2.iface.reference.TypeReference)((Instruction22c)inst).getReference()).getType();
				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);

				instructions.add(new NewArray(instLoc,
						((Instruction22c)inst).getRegisterA(),
						NewSiteReference.make(instLoc, TypeReference.findOrCreate(myClass.getClassLoader().getReference(),
								cname)),
								params, inst.getOpcode(), this));
				break;
			}
			//TODO: FILLED ARRAYS
			case FILLED_NEW_ARRAY: {
				int registerCount = ((Instruction35c)inst).getRegisterCount();
				int[] params = new int[1];
				params[0] = registerCount;
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
				{
					switch(i) {
					case 0:
						args[0] = ((Instruction35c)inst).getRegisterD();
						break;
					case 1:
						args[1] = ((Instruction35c)inst).getRegisterE();
						break;
					case 2:
						args[2] = ((Instruction35c)inst).getRegisterF();
						break;
					case 3:
						args[3] = ((Instruction35c)inst).getRegisterG();
						break;
					case 4:
						args[4] = ((Instruction35c)inst).getRegisterC();
						break;
					default:
						throw new RuntimeException("Illegal instruction at "
								+ instLoc + ": bad register count");
					}
				}

				String cname = ((org.jf.dexlib2.iface.reference.TypeReference)((Instruction35c)inst).getReference()).getType();
				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);

				NewSiteReference newSiteRef = NewSiteReference.make(instLoc, TypeReference.findOrCreate(myClass.getClassLoader().getReference(),
						cname));
				TypeReference myTypeRef = TypeReference.findOrCreate(myClass.getClassLoader().getReference(), newSiteRef.getDeclaredType().getArrayElementType().getName().toString());

				instructions.add(new NewArrayFilled(instLoc, getReturnReg(),
						newSiteRef, myTypeRef, params, args, inst.getOpcode(), this));
				break;
			}
			case FILLED_NEW_ARRAY_RANGE: {
				int registerCount = ((Instruction3rc)inst).getRegisterCount();
				int[] params = new int[1];
				params[0] = registerCount;
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
					args[i] = ((Instruction3rc)inst).getStartRegister() + i;

				String cname = ((org.jf.dexlib2.iface.reference.TypeReference)((Instruction3rc)inst).getReference()).getType();
				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);


				NewSiteReference newSiteRef = NewSiteReference.make(instLoc, TypeReference.findOrCreate(myClass.getClassLoader().getReference(),
						cname));
				TypeReference myTypeRef = TypeReference.findOrCreate(myClass.getClassLoader().getReference(), newSiteRef.getDeclaredType().getArrayElementType().getName().toString());


				instructions.add(new NewArrayFilled(instLoc, getReturnReg(), newSiteRef, myTypeRef, params, args, inst.getOpcode(), this));
				break;
			}
			case FILL_ARRAY_DATA:
				// System.out.println("Array Reference: " + ((Instruction31t)inst).getRegisterA());
				// System.out.println("Table Address Offset: " + ((Instruction31t)inst).getCodeOffset());

				TypeReference arrayElementType = findOutArrayElementType(inst, instructions.toArray(new Instruction[0]), instCounter);
				instructions.add(new ArrayFill(instLoc, ((Instruction31t)inst).getRegisterA(), ((Instruction31t)inst).getCodeOffset(),
						TypeReference.findOrCreate(myClass.getClassLoader().getReference(), arrayElementType.getName().toString()), inst.getOpcode(), this));
				break;
			case THROW:
				instructions.add(new Throw(instLoc, ((Instruction11x)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case GOTO:
				instructions.add(new Goto(instLoc, ((Instruction10t)inst).getCodeOffset(), inst.getOpcode(), this));
				break;
			case GOTO_16:
				instructions.add(new Goto(instLoc, ((Instruction20t)inst).getCodeOffset(), inst.getOpcode(), this));
				break;
			case GOTO_32:
				instructions.add(new Goto(instLoc, ((Instruction30t)inst).getCodeOffset(), inst.getOpcode(), this));
				break;

			case PACKED_SWITCH:
			case SPARSE_SWITCH:
				instructions.add(new Switch(instLoc, ((Instruction31t)inst).getRegisterA(), ((Instruction31t)inst).getCodeOffset(), inst.getOpcode(), this));
				break;

			case CMPL_FLOAT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.CMPL_FLOAT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case CMPG_FLOAT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.CMPG_FLOAT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case CMPL_DOUBLE:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.CMPL_DOUBLE, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case CMPG_DOUBLE:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.CMPG_DOUBLE, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case CMP_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.CMPL_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case IF_EQ:
				instructions.add(new Branch.BinaryBranch(instLoc, ((Instruction22t)inst).getCodeOffset(),
						Branch.BinaryBranch.CompareOp.EQ, ((Instruction22t)inst).getRegisterA(),
						((Instruction22t)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case IF_NE:
				instructions.add(new Branch.BinaryBranch(instLoc, ((Instruction22t)inst).getCodeOffset(),
						Branch.BinaryBranch.CompareOp.NE, ((Instruction22t)inst).getRegisterA(),
						((Instruction22t)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case IF_LT:
				instructions.add(new Branch.BinaryBranch(instLoc, ((Instruction22t)inst).getCodeOffset(),
						Branch.BinaryBranch.CompareOp.LT, ((Instruction22t)inst).getRegisterA(),
						((Instruction22t)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case IF_GE:
				instructions.add(new Branch.BinaryBranch(instLoc, ((Instruction22t)inst).getCodeOffset(),
						Branch.BinaryBranch.CompareOp.GE, ((Instruction22t)inst).getRegisterA(),
						((Instruction22t)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case IF_GT:
				instructions.add(new Branch.BinaryBranch(instLoc, ((Instruction22t)inst).getCodeOffset(),
						Branch.BinaryBranch.CompareOp.GT, ((Instruction22t)inst).getRegisterA(),
						((Instruction22t)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case IF_LE:
				instructions.add(new Branch.BinaryBranch(instLoc, ((Instruction22t)inst).getCodeOffset(),
						Branch.BinaryBranch.CompareOp.LE, ((Instruction22t)inst).getRegisterA(),
						((Instruction22t)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case IF_EQZ:
				instructions.add(new Branch.UnaryBranch(instLoc,
						((Instruction21t)inst).getCodeOffset(), Branch.UnaryBranch.CompareOp.EQZ,
						((Instruction21t)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case IF_NEZ:
				instructions.add(new Branch.UnaryBranch(instLoc,
						((Instruction21t)inst).getCodeOffset(), Branch.UnaryBranch.CompareOp.NEZ,
						((Instruction21t)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case IF_LTZ:
				instructions.add(new Branch.UnaryBranch(instLoc,
						((Instruction21t)inst).getCodeOffset(), Branch.UnaryBranch.CompareOp.LTZ,
						((Instruction21t)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case IF_GEZ:
				instructions.add(new Branch.UnaryBranch(instLoc,
						((Instruction21t)inst).getCodeOffset(), Branch.UnaryBranch.CompareOp.GEZ,
						((Instruction21t)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case IF_GTZ:
				instructions.add(new Branch.UnaryBranch(instLoc,
						((Instruction21t)inst).getCodeOffset(), Branch.UnaryBranch.CompareOp.GTZ,
						((Instruction21t)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case IF_LEZ:
				instructions.add(new Branch.UnaryBranch(instLoc,
						((Instruction21t)inst).getCodeOffset(), Branch.UnaryBranch.CompareOp.LEZ,
						((Instruction21t)inst).getRegisterA(), inst.getOpcode(), this));
				break;
			case AGET:
				instructions.add(new ArrayGet(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_int, inst.getOpcode(), this));
				break;
			case AGET_WIDE:
				instructions.add(new ArrayGet(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_wide, inst.getOpcode(), this));
				break;
			case AGET_OBJECT:
				instructions.add(new ArrayGet(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_object, inst.getOpcode(), this));
				break;
			case AGET_BOOLEAN:
				instructions.add(new ArrayGet(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_boolean, inst.getOpcode(), this));
				break;
			case AGET_BYTE:
				instructions.add(new ArrayGet(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_byte, inst.getOpcode(), this));
				break;
			case AGET_CHAR:
				instructions.add(new ArrayGet(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_char, inst.getOpcode(), this));
				break;
			case AGET_SHORT:
				instructions.add(new ArrayGet(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_short, inst.getOpcode(), this));
				break;
			case APUT:
				instructions.add(new ArrayPut(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_int, inst.getOpcode(), this));
				break;
			case APUT_WIDE:
				instructions.add(new ArrayPut(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_wide, inst.getOpcode(), this));
				break;
			case APUT_OBJECT:
				instructions.add(new ArrayPut(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_object, inst.getOpcode(), this));
				break;
			case APUT_BOOLEAN:
				instructions.add(new ArrayPut(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_boolean, inst.getOpcode(), this));
				break;
			case APUT_BYTE:
				instructions.add(new ArrayPut(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_byte, inst.getOpcode(), this));
				break;
			case APUT_CHAR:
				instructions.add(new ArrayPut(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_char, inst.getOpcode(), this));
				break;
			case APUT_SHORT:
				instructions.add(new ArrayPut(instLoc, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(), ((Instruction23x)inst).getRegisterC(), Type.t_short, inst.getOpcode(), this));
				break;
			case IGET:
			case IGET_WIDE:
			case IGET_OBJECT:
			case IGET_BOOLEAN:
			case IGET_BYTE:
			case IGET_CHAR:
			case IGET_SHORT: {
				String cname = ((FieldReference)((Instruction22c)inst).getReference()).getDefiningClass();
				String fname = ((FieldReference)((Instruction22c)inst).getReference()).getName();
				String ftname = ((FieldReference)((Instruction22c)inst).getReference()).getType();

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);
				if (fname.endsWith(";"))
					fname = fname.substring(0,fname.length()-1);
				if (ftname.endsWith(";"))
					ftname = ftname.substring(0,ftname.length()-1);

				instructions.add(new GetField.GetInstanceField(
						instLoc, ((Instruction22c)inst).getRegisterA(), ((Instruction22c)inst).getRegisterB(),
						cname, fname, ftname, inst.getOpcode(), this));
				break;
			}
			case IPUT:
			case IPUT_WIDE:
			case IPUT_OBJECT:
			case IPUT_BOOLEAN:
			case IPUT_BYTE:
			case IPUT_CHAR:
			case IPUT_SHORT: {
				String cname = ((FieldReference)((Instruction22c)inst).getReference()).getDefiningClass();
				String fname = ((FieldReference)((Instruction22c)inst).getReference()).getName();
				String ftname = ((FieldReference)((Instruction22c)inst).getReference()).getType();

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);
				if (fname.endsWith(";"))
					fname = fname.substring(0,fname.length()-1);
				if (ftname.endsWith(";"))
					ftname = ftname.substring(0,ftname.length()-1);

				instructions.add(new PutField.PutInstanceField(
						instLoc, ((TwoRegisterInstruction)inst).getRegisterA(), ((TwoRegisterInstruction)inst).getRegisterB(),
						cname, fname, ftname, inst.getOpcode(), this));
				break;
			}
			case SGET:
			case SGET_WIDE:
			case SGET_OBJECT:
			case SGET_BOOLEAN:
			case SGET_BYTE:
			case SGET_CHAR:
			case SGET_SHORT: {
				String cname = ((FieldReference)((Instruction21c)inst).getReference()).getDefiningClass();
				String fname = ((FieldReference)((Instruction21c)inst).getReference()).getName();
				String ftname = ((FieldReference)((Instruction21c)inst).getReference()).getType();

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);
				if (fname.endsWith(";"))
					fname = fname.substring(0,fname.length()-1);
				if (ftname.endsWith(";"))
					ftname = ftname.substring(0,ftname.length()-1);

				instructions.add(new GetField.GetStaticField(instLoc,
						((Instruction21c)inst).getRegisterA(), cname, fname, ftname, inst.getOpcode(), this));
				break;
			}
			case SPUT:
			case SPUT_WIDE:
			case SPUT_OBJECT:
			case SPUT_BOOLEAN:
			case SPUT_BYTE:
			case SPUT_CHAR:
			case SPUT_SHORT: {
				String cname = ((FieldReference)((Instruction21c)inst).getReference()).getDefiningClass();
				String fname = ((FieldReference)((Instruction21c)inst).getReference()).getName();
				String ftname = ((FieldReference)((Instruction21c)inst).getReference()).getType();

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);
				if (fname.endsWith(";"))
					fname = fname.substring(0,fname.length()-1);
				if (ftname.endsWith(";"))
					ftname = ftname.substring(0,ftname.length()-1);

				instructions.add(new PutField.PutStaticField(instLoc,
						((Instruction21c)inst).getRegisterA(), cname, fname, ftname, inst.getOpcode(), this));
				break;
			}
			case INVOKE_VIRTUAL: {
				int registerCount = ((Instruction35c)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
				{
					switch(i) {
					case 0:
						args[0] = ((Instruction35c)inst).getRegisterC();
						break;
					case 1:
						args[1] = ((Instruction35c)inst).getRegisterD();
						break;
					case 2:
						args[2] = ((Instruction35c)inst).getRegisterE();
						break;
					case 3:
						args[3] = ((Instruction35c)inst).getRegisterF();
						break;
					case 4:
						args[4] = ((Instruction35c)inst).getRegisterG();
						break;
					default:
						throw new RuntimeException("Illegal instruction at "
								+ instLoc + ": bad register count");
					}
				}

				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);
				//              if (mname.endsWith(";"))
				//                  mname = mname.substring(0,mname.length()-1);
				//              if (pname.endsWith(";"))
				//                  pname = pname.substring(0,pname.length()-1);

				//              for (IMethod m: this.myClass.loader.lookupClass(TypeName.findOrCreate(cname)).getDeclaredMethods())
				//                  System.out.println(m.getDescriptor().toString());

				handleINVOKE_VIRTUAL(instLoc, cname, mname, pname, args, inst.getOpcode());
				//instructions.add(new Invoke.InvokeVirtual(instLoc, cname, mname, pname, args, inst.opcode, this));
				//logger.debug("\t" + inst.opcode.toString() + " class: "+ cname + ", method name: " + mname + ", prototype string: " + pname);

				break;
			}
			case INVOKE_SUPER: {
				int registerCount = ((Instruction35c)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
				{
					switch(i) {
					case 0:
						args[0] = ((Instruction35c)inst).getRegisterC();
						break;
					case 1:
						args[1] = ((Instruction35c)inst).getRegisterD();
						break;
					case 2:
						args[2] = ((Instruction35c)inst).getRegisterE();
						break;
					case 3:
						args[3] = ((Instruction35c)inst).getRegisterF();
						break;
					case 4:
						args[4] = ((Instruction35c)inst).getRegisterG();
						break;
					default:
						throw new RuntimeException("Illegal instruction at "
								+ instLoc + ": bad register count");
					}
				}

				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);


				instructions.add(new Invoke.InvokeSuper(instLoc,
						cname, mname, pname, args, inst.getOpcode(), this));
				break;
			}
			case INVOKE_DIRECT: {
				int registerCount = ((Instruction35c)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
				{
					switch(i) {
					case 0:
						args[0] = ((Instruction35c)inst).getRegisterC();
						break;
					case 1:
						args[1] = ((Instruction35c)inst).getRegisterD();
						break;
					case 2:
						args[2] = ((Instruction35c)inst).getRegisterE();
						break;
					case 3:
						args[3] = ((Instruction35c)inst).getRegisterF();
						break;
					case 4:
						args[4] = ((Instruction35c)inst).getRegisterG();
						break;
					default:
						throw new RuntimeException("Illegal instruction at "
								+ instLoc + ": bad register count");
					}
				}

				//              logger.debug(inst.opcode.toString() + " class: "+((MethodIdItem)((Instruction35c)inst).getReferencedItem()).getContainingClass().getTypeDescriptor() + ", method name: " + ((MethodIdItem)((Instruction35c)inst).getReferencedItem()).getMethodName().getStringValue() + ", prototype string: " + ((MethodIdItem)((Instruction35c)inst).getReferencedItem()).getPrototype().getPrototypeString());
				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);


				instructions.add(new Invoke.InvokeDirect(instLoc,
						cname, mname, pname, args, inst.getOpcode(), this));

				break;
			}
			case INVOKE_STATIC: {
				int registerCount = ((Instruction35c)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
				{
					switch(i) {
					case 0:
						args[0] = ((Instruction35c)inst).getRegisterC();
						break;
					case 1:
						args[1] = ((Instruction35c)inst).getRegisterD();
						break;
					case 2:
						args[2] = ((Instruction35c)inst).getRegisterE();
						break;
					case 3:
						args[3] = ((Instruction35c)inst).getRegisterF();
						break;
					case 4:
						args[4] = ((Instruction35c)inst).getRegisterG();
						break;
					default:
						throw new RuntimeException("Illegal instruction at "
								+ instLoc + ": bad register count");
					}
				}

				//logger.debug(inst.opcode.toString() + " class: "+((MethodIdItem)((Instruction35c)inst).getReferencedItem()).getContainingClass().getTypeDescriptor() + ", method name: " + ((MethodIdItem)((Instruction35c)inst).getReferencedItem()).getMethodName().getStringValue() + ", prototype string: " + ((MethodIdItem)((Instruction35c)inst).getReferencedItem()).getPrototype().getPrototypeString());
				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);



				instructions.add(new Invoke.InvokeStatic(instLoc, cname, mname, pname, args, inst.getOpcode(), this));

				break;
			}
			case INVOKE_INTERFACE: {
				int registerCount = ((Instruction35c)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
				{
					switch(i) {
					case 0:
						args[0] = ((Instruction35c)inst).getRegisterC();
						break;
					case 1:
						args[1] = ((Instruction35c)inst).getRegisterD();
						break;
					case 2:
						args[2] = ((Instruction35c)inst).getRegisterE();
						break;
					case 3:
						args[3] = ((Instruction35c)inst).getRegisterF();
						break;
					case 4:
						args[4] = ((Instruction35c)inst).getRegisterG();
						break;
					default:
						throw new RuntimeException("Illegal instruction at "
								+ instLoc + ": bad register count");
					}
				}

				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction35c)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);


				instructions.add(new Invoke.InvokeInterface(instLoc,
						cname, mname, pname, args, inst.getOpcode(), this));
				break;
			}
			case INVOKE_VIRTUAL_RANGE: {
				int registerCount = ((Instruction3rc)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
					args[i] = ((Instruction3rc)inst).getStartRegister() + i;

				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);


				instructions.add(new Invoke.InvokeVirtual(instLoc,
						cname, mname, pname, args, inst.getOpcode(), this));
				break;
			}
			case INVOKE_SUPER_RANGE: {
				int registerCount = ((Instruction3rc)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
					args[i] = ((Instruction3rc)inst).getStartRegister() + i;

				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getName();
        String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);

				instructions.add(new Invoke.InvokeSuper(instLoc,
						cname, mname, pname, args, inst.getOpcode(), this));
				break;
			}
			case INVOKE_DIRECT_RANGE: {
				int registerCount = ((Instruction3rc)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
					args[i] = ((Instruction3rc)inst).getStartRegister() + i;

				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);

				instructions.add(new Invoke.InvokeDirect(instLoc,
						cname, mname, pname, args, inst.getOpcode(), this));
				break;
			}
			case INVOKE_STATIC_RANGE: {
				int registerCount = ((Instruction3rc)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
					args[i] = ((Instruction3rc)inst).getStartRegister() + i;

				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);


				instructions.add(new Invoke.InvokeStatic(instLoc, cname, mname, pname, args, inst.getOpcode(), this));

				break;
			}
			case INVOKE_INTERFACE_RANGE: {
				int registerCount = ((Instruction3rc)inst).getRegisterCount();
				int[] args = new int[registerCount];

				for (int i = 0; i < registerCount; i++)
					args[i] = ((Instruction3rc)inst).getStartRegister() + i;

				String cname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getDefiningClass();
				String mname = ((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference()).getName();
				String pname = DexUtil.getSignature((org.jf.dexlib2.iface.reference.MethodReference)((Instruction3rc)inst).getReference());

				if (cname.endsWith(";"))
					cname = cname.substring(0,cname.length()-1);

				instructions.add(new Invoke.InvokeInterface(instLoc,
						cname, mname, pname, args, inst.getOpcode(), this));
				break;
			}
			case NEG_INT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.NEGINT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case NOT_INT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.NOTINT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case NEG_LONG:
				instructions.add(new UnaryOperation(instLoc,
						OpID.NEGLONG, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case NOT_LONG:
				instructions.add(new UnaryOperation(instLoc,
						OpID.NOTLONG, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case NEG_FLOAT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.NEGFLOAT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case NEG_DOUBLE:
				instructions.add(new UnaryOperation(instLoc,
						OpID.NEGDOUBLE, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case INT_TO_LONG:
				instructions.add(new UnaryOperation(instLoc,
						OpID.INTTOLONG, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case INT_TO_FLOAT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.INTTOFLOAT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case INT_TO_DOUBLE:
				instructions.add(new UnaryOperation(instLoc,
						OpID.INTTODOUBLE, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case LONG_TO_INT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.LONGTOINT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case LONG_TO_FLOAT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.LONGTOFLOAT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case LONG_TO_DOUBLE:
				instructions.add(new UnaryOperation(instLoc,
						OpID.LONGTODOUBLE, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case FLOAT_TO_INT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.FLOATTOINT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case FLOAT_TO_LONG:
				instructions.add(new UnaryOperation(instLoc,
						OpID.FLOATTOLONG, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case FLOAT_TO_DOUBLE:
				instructions.add(new UnaryOperation(instLoc,
						OpID.FLOATTODOUBLE, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case DOUBLE_TO_INT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.DOUBLETOINT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case DOUBLE_TO_LONG:
				instructions.add(new UnaryOperation(instLoc,
						OpID.DOUBLETOLONG, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case DOUBLE_TO_FLOAT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.DOUBLETOFLOAT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case INT_TO_BYTE:
				instructions.add(new UnaryOperation(instLoc,
						OpID.INTTOBYTE, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case INT_TO_CHAR:
				instructions.add(new UnaryOperation(instLoc,
						OpID.INTTOCHAR, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case INT_TO_SHORT:
				instructions.add(new UnaryOperation(instLoc,
						OpID.INTTOSHORT, ((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case ADD_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.ADD_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case SUB_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SUB_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case MUL_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.MUL_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case DIV_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.DIV_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case REM_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.REM_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case AND_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.AND_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case OR_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.OR_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case XOR_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.XOR_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case SHL_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SHL_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case SHR_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SHR_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case USHR_INT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.USHR_INT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case ADD_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.ADD_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case SUB_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SUB_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case MUL_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.MUL_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case DIV_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.DIV_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case REM_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.REM_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case AND_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.AND_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case OR_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.OR_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case XOR_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.XOR_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case SHL_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SHL_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case SHR_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SHR_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case USHR_LONG:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.USHR_LONG, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case ADD_FLOAT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.ADD_FLOAT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case SUB_FLOAT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SUB_FLOAT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case MUL_FLOAT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.MUL_FLOAT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case DIV_FLOAT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.DIV_FLOAT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case REM_FLOAT:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.REM_FLOAT, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case ADD_DOUBLE:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.ADD_DOUBLE, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case SUB_DOUBLE:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SUB_DOUBLE, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case MUL_DOUBLE:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.MUL_DOUBLE, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case DIV_DOUBLE:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.DIV_DOUBLE, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case REM_DOUBLE:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.REM_DOUBLE, ((Instruction23x)inst).getRegisterA(),
						((Instruction23x)inst).getRegisterB(),((Instruction23x)inst).getRegisterC(), inst.getOpcode(), this));
				break;
			case ADD_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.ADD_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case SUB_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SUB_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MUL_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.MUL_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case DIV_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.DIV_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case REM_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.REM_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case AND_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.AND_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case OR_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.OR_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case XOR_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.XOR_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case SHL_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SHL_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case SHR_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SHR_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case USHR_INT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.USHR_INT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case ADD_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.ADD_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case SUB_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SUB_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MUL_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.MUL_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case DIV_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.DIV_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case REM_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.REM_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case AND_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.AND_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case OR_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.OR_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case XOR_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.XOR_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case SHL_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SHL_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case SHR_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SHR_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case USHR_LONG_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.USHR_LONG, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case ADD_FLOAT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.ADD_FLOAT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case SUB_FLOAT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SUB_FLOAT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MUL_FLOAT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.MUL_FLOAT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case DIV_FLOAT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.DIV_FLOAT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case REM_FLOAT_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.REM_FLOAT, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case ADD_DOUBLE_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.ADD_DOUBLE, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case SUB_DOUBLE_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.SUB_DOUBLE, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case MUL_DOUBLE_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.MUL_DOUBLE, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case DIV_DOUBLE_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.DIV_DOUBLE, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case REM_DOUBLE_2ADDR:
				instructions.add(new BinaryOperation(instLoc,
						BinaryOperation.OpID.REM_DOUBLE, ((Instruction12x)inst).getRegisterA(),
						((Instruction12x)inst).getRegisterA(), ((Instruction12x)inst).getRegisterB(), inst.getOpcode(), this));
				break;
			case ADD_INT_LIT16: {
				Literal lit = new Literal.LongLiteral(((Instruction22s)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.ADD_INT,
						((Instruction22s)inst).getRegisterA(), ((Instruction22s)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case RSUB_INT: {
				Literal lit = new Literal.LongLiteral(((Instruction22s)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.RSUB_INT,
						((Instruction22s)inst).getRegisterA(), ((Instruction22s)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case MUL_INT_LIT16: {
				Literal lit = new Literal.LongLiteral(((Instruction22s)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.MUL_INT,
						((Instruction22s)inst).getRegisterA(), ((Instruction22s)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case DIV_INT_LIT16: {
				Literal lit = new Literal.LongLiteral(((Instruction22s)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.DIV_INT,
						((Instruction22s)inst).getRegisterA(), ((Instruction22s)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case REM_INT_LIT16: {
				Literal lit = new Literal.LongLiteral(((Instruction22s)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.REM_INT,
						((Instruction22s)inst).getRegisterA(), ((Instruction22s)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case AND_INT_LIT16: {
				Literal lit = new Literal.LongLiteral(((Instruction22s)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.AND_INT,
						((Instruction22s)inst).getRegisterA(), ((Instruction22s)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case OR_INT_LIT16: {
				Literal lit = new Literal.LongLiteral(((Instruction22s)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.OR_INT,
						((Instruction22s)inst).getRegisterA(), ((Instruction22s)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case XOR_INT_LIT16: {
				Literal lit = new Literal.LongLiteral(((Instruction22s)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.XOR_INT,
						((Instruction22s)inst).getRegisterA(), ((Instruction22s)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case ADD_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.ADD_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case RSUB_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.RSUB_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case MUL_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.MUL_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case DIV_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.DIV_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case REM_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.REM_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case AND_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.AND_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case OR_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.OR_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case XOR_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.XOR_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case SHL_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.SHL_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case SHR_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.SHR_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			case USHR_INT_LIT8: {
				Literal lit = new Literal.LongLiteral(((Instruction22b)inst).getWideLiteral());
				instructions.add(new BinaryLiteralOperation(instLoc, BinaryLiteralOperation.OpID.USHR_INT,
						((Instruction22b)inst).getRegisterA(), ((Instruction22b)inst).getRegisterB(), lit, inst.getOpcode(), this));
				break;
			}
			default:
				throw new RuntimeException("not implemented instruction: 0x"
						+ inst.getOpcode().toString() + " in " + eMethod.getDefiningClass() + ':' + eMethod.getName());

			}
			currentCodeAddress += inst.getCodeUnits();
		}

		//// comment out start
		////        Instruction[] iinstructions = new Instruction[instrucs.length];
		//      instructions = new InsructionArray();
		//
		//
		//      for (int i = 0; i < instrucs.length; i++) {
		//          org.jf.dexlib.Code.Instruction instruction = instrucs[i];
		//
		//
		//          System.out.println(instruction.toString());
		//          switch (instruction.getFormat()) {
		//
		//  /*
		//-         Format10t(Instruction10t.Factory, 2),
		//-         Format10x(Instruction10x.Factory, 2),
		//-         Format11n(Instruction11n.Factory, 2),
		//-         Format11x(Instruction11x.Factory, 2),
		//-         Format12x(Instruction12x.Factory, 2),
		//-         Format20t(Instruction20t.Factory, 4),
		//-         Format21c(Instruction21c.Factory, 4),
		//          Format21h(Instruction21h.Factory, 4),
		//          Format21s(Instruction21s.Factory, 4),
		//          Format21t(Instruction21t.Factory, 4),
		//          Format22b(Instruction22b.Factory, 4),
		//          Format22c(Instruction22c.Factory, 4),
		//          Format22cs(Instruction22cs.Factory, 4),
		//          Format22s(Instruction22s.Factory, 4),
		//          Format22t(Instruction22t.Factory, 4),
		//          Format22x(Instruction22x.Factory, 4),
		//          Format23x(Instruction23x.Factory, 4),
		//-         Format30t(Instruction30t.Factory, 6),
		//          Format31c(Instruction31c.Factory, 6),
		//          Format31i(Instruction31i.Factory, 6),
		//          Format31t(Instruction31t.Factory, 6),
		//          Format32x(Instruction32x.Factory, 6),
		//          Format35c(Instruction35c.Factory, 6),
		//          Format35s(Instruction35s.Factory, 6),
		//          Format35ms(Instruction35ms.Factory, 6),
		//          Format3rc(Instruction3rc.Factory, 6),
		//          Format3rms(Instruction3rms.Factory, 6),
		//          Format51l(Instruction51l.Factory, 10),
		//          ArrayData(null, -1, true),
		//          PackedSwitchData(null, -1, true),
		//          SparseSwitchData(null, -1, true),
		//          UnresolvedOdexInstruction(null, -1, false),
		//*/
		//          case Format10t: { //goto
		//              
		//
		//              Instruction10t dInst = (Instruction10t)instruction;
		//
		//              int offset = dInst.getCodeOffset();
		//              instructions.add(new Goto(i,offset));
		//
		//              break;
		//          }
		//          case Format10x: {
		//              
		//              switch(instruction.opcode) {
		//              case RETURN_VOID: {
		//                  instructions.add(new Return.ReturnVoid(i));
		//                  break;
		//              }
		//              default:
		//                  break;
		//              }
		//
		//              break;
		//          }
		//
		//          case Format11n: {
		//              
		//              Instruction11n dInst = (Instruction11n) instruction;
		//
		//              System.out.println("here1");
		//              int a = (int)dInst.getLiteral();
		//              System.out.println("here2");
		//              Register b = regBank.get(dInst.getRegisterA());
		//              System.out.println("here3");
		//
		//              Constant.IntConstant c = new Constant.IntConstant(1, 2, b);
		//              //instructions.add(c);
		//              System.out.println("here5");
		//              instructions.add(new Constant.IntConstant(i,
		//                      (int)dInst.getLiteral(), regBank.get(dInst.getRegisterA())));
		//              System.out.println("here4");
		//              break;
		//          }
		//
		//          case Format11x: {
		//              /*
		//               *     MOVE_RESULT((byte)0x0a, "move-result", ReferenceType.none, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//    MOVE_RESULT_WIDE((byte)0x0b, "move-result-wide", ReferenceType.none, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//    MOVE_RESULT_OBJECT((byte)0x0c, "move-result-object", ReferenceType.none, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//    MOVE_EXCEPTION((byte)0x0d, "move-exception", ReferenceType.none, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//    RETURN((byte)0x0f, "return", ReferenceType.none, Format.Format11x),
		//    RETURN_WIDE((byte)0x10, "return-wide", ReferenceType.none, Format.Format11x),
		//    RETURN_OBJECT((byte)0x11, "return-object", ReferenceType.none, Format.Format11x),
		//    MONITOR_ENTER((byte)0x1d, "monitor-enter", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//    MONITOR_EXIT((byte)0x1e, "monitor-exit", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//    THROW((byte)0x27, "throw", ReferenceType.none, Format.Format11x, Opcode.CAN_THROW),
		//               */
		//              
		//              Instruction11x dInst = (Instruction11x) instruction;
		//
		//              switch (dInst.opcode) {
		//              case MOVE_RESULT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          UnaryOperation.OpID.MOVE, regBank.get(dInst.getRegisterA()),
		//                          regBank.getReturnReg()));
		//                  break;
		//              }
		//              case MOVE_RESULT_WIDE: {
		//                  instructions.add(new UnaryOperation(i,
		//                          UnaryOperation.OpID.MOVE_WIDE,
		//                          regBank.get(dInst.getRegisterA()), regBank.getReturnReg()));
		//                  break;
		//              }
		//              case MOVE_RESULT_OBJECT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          UnaryOperation.OpID.MOVE, regBank.get(dInst.getRegisterA()),
		//                          regBank.getReturnReg()));
		//                  break;
		//              }
		//              case MOVE_EXCEPTION: {
		//                  instructions.add(new UnaryOperation(i,
		//                          UnaryOperation.OpID.MOVE, regBank.get(dInst.getRegisterA()),
		//                          regBank.getReturnExceptionReg()));
		//                  break;
		//              }
		//              case RETURN: {
		//                  instructions.add(new Return.ReturnSingle(i,
		//                          regBank.get(dInst.getRegisterA())));
		//                  break;
		//              }
		//              case RETURN_WIDE: {
		//                  instructions.add(new Return.ReturnDouble(i,
		//                          regBank.get(dInst.getRegisterA()), regBank.get(dInst.getRegisterA() + 1)));
		//                  break;
		//              }
		//              case RETURN_OBJECT: {
		//                  instructions.add(new Return.ReturnSingle(i,
		//                          regBank.get(dInst.getRegisterA())));
		//                  break;
		//              }
		//              case MONITOR_ENTER: {
		//                  instructions.add(new Monitor(i, true, regBank
		//                          .get(dInst.getRegisterA())));
		//                  break;
		//              }
		//              case MONITOR_EXIT: {
		//                  instructions.add(new Monitor(i, false, regBank
		//                          .get(dInst.getRegisterA())));
		//                  break;
		//              }
		//              case THROW: {
		//                  instructions.add(new Throw(i, regBank
		//                          .get(dInst.getRegisterA())));
		//                  break;
		//              }
		//              default:
		//                  break;
		//              }
		//              break;
		//          }
		//
		//          case Format12x: {
		//              
		//              Instruction12x dInst = (Instruction12x) instruction;
		//              int destination = dInst.getRegisterA();
		//              int source = dInst.getRegisterB();
		//
		//              switch(dInst.opcode) {
		//              //     MOVE((byte)0x01, "move", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case MOVE: {
		//                  instructions.add(new UnaryOperation(i,
		//                          UnaryOperation.OpID.MOVE, regBank.get(destination),
		//                          regBank.get(source)));
		//                  break;
		//              }
		//              //    MOVE_WIDE((byte)0x04, "move-wide", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case MOVE_WIDE: {
		//                  instructions.add(new UnaryOperation(i,
		//                          UnaryOperation.OpID.MOVE_WIDE,
		//                          regBank.get(destination), regBank.get(source)));
		//                  break;
		//              }
		//              //    MOVE_OBJECT((byte)0x07, "move-object", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case MOVE_OBJECT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          UnaryOperation.OpID.MOVE, regBank.get(destination),
		//                          regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    ARRAY_LENGTH((byte)0x21, "array-length", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case ARRAY_LENGTH: {
		//                  instructions.add(new ArrayLength(i, regBank
		//                          .get(destination), regBank.get(source)));
		//                  break;
		//              }
		//              //    NEG_INT((byte)0x7b, "neg-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case NEG_INT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.NEGINT, regBank.get(destination), regBank.get(source)));
		//                  break;
		//              }
		//              //    NOT_INT((byte)0x7c, "not-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case NOT_INT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.NOTINT, regBank.get(destination), regBank.get(source)));
		//                  break;
		//              }
		//              //    NEG_LONG((byte)0x7d, "neg-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case NEG_LONG: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.NEGLONG, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    NOT_LONG((byte)0x7e, "not-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case NOT_LONG: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.NOTLONG, regBank.get(destination), regBank.get(source)));
		//                  break;
		//              }
		//              //    NEG_FLOAT((byte)0x7f, "neg-float", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case NEG_FLOAT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.NEGFLOAT, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//
		//              }
		//              //    NEG_DOUBLE((byte)0x80, "neg-double", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case NEG_DOUBLE: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.NEGDOUBLE, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    INT_TO_LONG((byte)0x81, "int-to-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case INT_TO_LONG: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.INTTOLONG, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    INT_TO_FLOAT((byte)0x82, "int-to-float", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case INT_TO_FLOAT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.INTTOFLOAT, regBank.get(destination), regBank.get(source)));
		//                  break;
		//              }
		//              //    INT_TO_DOUBLE((byte)0x83, "int-to-double", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case INT_TO_DOUBLE: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.INTTODOUBLE, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    LONG_TO_INT((byte)0x84, "long-to-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case LONG_TO_INT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.LONGTOINT, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    LONG_TO_FLOAT((byte)0x85, "long-to-float", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case LONG_TO_FLOAT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.LONGTOFLOAT, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    LONG_TO_DOUBLE((byte)0x86, "long-to-double", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case LONG_TO_DOUBLE: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.LONGTODOUBLE, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    FLOAT_TO_INT((byte)0x87, "float-to-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case FLOAT_TO_INT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.FLOATTOINT, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    FLOAT_TO_LONG((byte)0x88, "float-to-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case FLOAT_TO_LONG: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.FLOATTOLONG, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    FLOAT_TO_DOUBLE((byte)0x89, "float-to-double", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case FLOAT_TO_DOUBLE: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.FLOATTODOUBLE, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    DOUBLE_TO_INT((byte)0x8a, "double-to-int", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case DOUBLE_TO_INT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.DOUBLETOINT, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    DOUBLE_TO_LONG((byte)0x8b, "double-to-long", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case DOUBLE_TO_LONG: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.DOUBLETOLONG, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    DOUBLE_TO_FLOAT((byte)0x8c, "double-to-float", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case DOUBLE_TO_FLOAT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.DOUBLETOFLOAT, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    INT_TO_BYTE((byte)0x8d, "int-to-byte", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case INT_TO_BYTE: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.INTTOBYTE, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    INT_TO_CHAR((byte)0x8e, "int-to-char", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case INT_TO_CHAR: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.INTTOCHAR, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    INT_TO_SHORT((byte)0x8f, "int-to-short", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case INT_TO_SHORT: {
		//                  instructions.add(new UnaryOperation(i,
		//                          OpID.INTTOSHORT, regBank.get(destination), regBank.get(source)));
		//
		//                  break;
		//              }
		//              //    ADD_INT_2ADDR((byte)0xb0, "add-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case ADD_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.ADD_INT, d, d, s));
		//                  break;
		//              }
		//              //    SUB_INT_2ADDR((byte)0xb1, "sub-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SUB_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.SUB_INT, d, d, s));
		//                  break;
		//              }
		//              //    MUL_INT_2ADDR((byte)0xb2, "mul-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case MUL_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.MUL_INT, d, d, s));
		//                  break;
		//              }
		//              //    DIV_INT_2ADDR((byte)0xb3, "div-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case DIV_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.DIV_INT, d, d, s));
		//                  break;
		//              }
		//              //    REM_INT_2ADDR((byte)0xb4, "rem-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case REM_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.REM_INT, d, d, s));
		//                  break;
		//              }
		//              //    AND_INT_2ADDR((byte)0xb5, "and-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case AND_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.AND_INT, d, d, s));
		//                  break;
		//              }
		//              //    OR_INT_2ADDR((byte)0xb6, "or-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case OR_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.OR_INT, d, d, s));
		//                  break;
		//              }
		//              //    XOR_INT_2ADDR((byte)0xb7, "xor-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case XOR_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.XOR_INT, d, d, s));
		//                  break;
		//              }
		//              //    SHL_INT_2ADDR((byte)0xb8, "shl-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SHL_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.SHL_INT, d, d, s));
		//                  break;
		//              }
		//              //    SHR_INT_2ADDR((byte)0xb9, "shr-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SHR_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.SHR_INT, d, d, s));
		//                  break;
		//              }
		//              //    USHR_INT_2ADDR((byte)0xba, "ushr-int/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case USHR_INT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.USHR_INT, d, d, s));
		//                  break;
		//              }
		//              //    ADD_LONG_2ADDR((byte)0xbb, "add-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case ADD_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.ADD_LONG, d, d, s));
		//                  break;
		//              }
		//              //    SUB_LONG_2ADDR((byte)0xbc, "sub-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case SUB_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.SUB_LONG, d, d, s));
		//                  break;
		//              }
		//              //    MUL_LONG_2ADDR((byte)0xbd, "mul-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case MUL_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.MUL_LONG, d, d, s));
		//                  break;
		//              }
		//              //    DIV_LONG_2ADDR((byte)0xbe, "div-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case DIV_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.DIV_LONG, d, d, s));
		//                  break;
		//              }
		//              //    REM_LONG_2ADDR((byte)0xbf, "rem-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case REM_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.REM_LONG, d, d, s));
		//                  break;
		//              }
		//              //    AND_LONG_2ADDR((byte)0xc0, "and-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case AND_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.AND_LONG, d, d, s));
		//                  break;
		//              }
		//              //    OR_LONG_2ADDR((byte)0xc1, "or-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case OR_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.OR_LONG, d, d, s));
		//                  break;
		//              }
		//              //    XOR_LONG_2ADDR((byte)0xc2, "xor-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case XOR_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.XOR_LONG, d, d, s));
		//                  break;
		//              }
		//              //    SHL_LONG_2ADDR((byte)0xc3, "shl-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case SHL_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.SHL_LONG, d, d, s));
		//                  break;
		//              }
		//              //    SHR_LONG_2ADDR((byte)0xc4, "shr-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case SHR_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.SHR_LONG, d, d, s));
		//                  break;
		//              }
		//              //    USHR_LONG_2ADDR((byte)0xc5, "ushr-long/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case USHR_LONG_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.USHR_LONG, d, d, s));
		//                  break;
		//              }
		//              //    ADD_FLOAT_2ADDR((byte)0xc6, "add-float/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case ADD_FLOAT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.ADD_FLOAT, d, d, s));
		//                  break;
		//              }
		//              //    SUB_FLOAT_2ADDR((byte)0xc7, "sub-float/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SUB_FLOAT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.SUB_FLOAT, d, d, s));
		//                  break;
		//              }
		//              //    MUL_FLOAT_2ADDR((byte)0xc8, "mul-float/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case MUL_FLOAT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.MUL_FLOAT, d, d, s));
		//                  break;
		//              }
		//              //    DIV_FLOAT_2ADDR((byte)0xc9, "div-float/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case DIV_FLOAT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.DIV_FLOAT, d, d, s));
		//                  break;
		//              }
		//              //    REM_FLOAT_2ADDR((byte)0xca, "rem-float/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case REM_FLOAT_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.REM_FLOAT, d, d, s));
		//                  break;
		//              }
		//              //    ADD_DOUBLE_2ADDR((byte)0xcb, "add-double/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case ADD_DOUBLE_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.ADD_DOUBLE, d, d, s));
		//                  break;
		//              }
		//              //    SUB_DOUBLE_2ADDR((byte)0xcc, "sub-double/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case SUB_DOUBLE_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.SUB_DOUBLE, d, d, s));
		//                  break;
		//              }
		//              //    MUL_DOUBLE_2ADDR((byte)0xcd, "mul-double/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case MUL_DOUBLE_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.MUL_DOUBLE, d, d, s));
		//                  break;
		//              }
		//              //    DIV_DOUBLE_2ADDR((byte)0xce, "div-double/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case DIV_DOUBLE_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.DIV_DOUBLE, d, d, s));
		//                  break;
		//              }
		//              //    REM_DOUBLE_2ADDR((byte)0xcf, "rem-double/2addr", ReferenceType.none, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case REM_DOUBLE_2ADDR: {
		//                  Register d = regBank.get(destination);
		//                  Register s = regBank.get(source);
		//                  instructions.add(new BinaryOperation(i,
		//                          BinaryOperation.OpID.REM_DOUBLE, d, d, s));
		//                  break;
		//              }
		//              default:
		//                  break;
		//              }
		//
		//          break;
		//          }
		//
		//          case Format20t: { //goto/16
		//              
		//
		//              Instruction20t dInst = (Instruction20t)instruction;
		//
		//              int offset = dInst.getCodeOffset();
		//              instructions.add(new Goto(i,offset));
		//              break;
		//          }
		//          case Format30t: { //goto/32
		//              
		//
		//              Instruction30t dInst = (Instruction30t)instruction;
		//
		//              int offset = dInst.getCodeOffset();
		//              instructions.add(new Goto(i,offset));
		//              break;
		//          }
		//
		//          case Format21c: {
		//              Instruction21c dInst = (Instruction21c) instruction;
		//              
		//
		//              switch (dInst.opcode) {
		//              //CONST_STRING((byte)0x1a, "const-string", ReferenceType.string, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case CONST_STRING: {
		//                  int destination = dInst.getRegisterA();
		//                  instructions.add(new Constant.StringConstant(i,
		//                          dInst.getReferencedItem().getConciseIdentity(), regBank.get(destination)));
		//
		//                  break;
		//              }
		//              //    CONST_CLASS((byte)0x1c, "const-class", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case CONST_CLASS: {
		//                  int destination = dInst.getRegisterA();
		//                  IClass value = this.myClass.getClassLoader().lookupClass(TypeName.findOrCreate(dInst.getReferencedItem().getConciseIdentity()));
		//
		//                  instructions.add(new Constant.ClassConstant(i,
		//                      value, regBank.get(destination)));
		//                  break;
		//              }
		//              //    CHECK_CAST((byte)0x1f, "check-cast", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case CHECK_CAST: {
		//                  int val = dInst.getRegisterA();
		//                  String type = dInst.getReferencedItem().getConciseIdentity();
		//                  instructions.add(new CheckCast(i, TypeReference
		//                          .findOrCreate(this.myClass.getClassLoader().getReference(), type), regBank
		//                          .get(val)));
		//
		//                  break;
		//              }
		//              //    NEW_INSTANCE((byte)0x22, "new-instance", ReferenceType.type, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case NEW_INSTANCE: {
		//                  int destination = dInst.getRegisterA();
		//                  String type = dInst.getReferencedItem().getConciseIdentity();
		//                  instructions.add(new New(i, regBank
		//                          .get(destination), NewSiteReference.make(i,
		//                          TypeReference
		//                                  .findOrCreate(this.myClass.getClassLoader().getReference(), type))));
		//                  break;
		//              }
		//              //    SGET((byte)0x60, "sget", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SGET:
		//              //    SGET_WIDE((byte)0x61, "sget-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              case SGET_WIDE:
		//              //    SGET_OBJECT((byte)0x62, "sget-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SGET_OBJECT:
		//              //    SGET_BOOLEAN((byte)0x63, "sget-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SGET_BOOLEAN:
		//              //    SGET_BYTE((byte)0x64, "sget-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SGET_BYTE:
		//              //    SGET_CHAR((byte)0x65, "sget-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SGET_CHAR:
		//              //    SGET_SHORT((byte)0x66, "sget-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              case SGET_SHORT: {
		//
		//                  /*  TODO
		//                  Register destination = regBank.get(dInst.getRegisterA());
		//                  Register source = regBank.get(dInst.getReferencedItem().getOffset());
		//                  int fieldIndex = codes[pc++];
		//                  this.eMethod
		//                  String clazzName = fieldClasses[fieldIndex];
		//                  String fieldName = fieldNames[fieldIndex];
		//                  String fieldType = fieldTypes[fieldIndex];
		//                  // getField(false, frame, source, fieldIndex, destination);
		//                  instructions.add(new GetField.GetInstanceField(
		//                          instLoc, destination, source, clazzName, fieldName,
		//                          fieldType));
		//*/
		//                  break;
		//              }
		//              //    SPUT((byte)0x67, "sput", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SPUT_WIDE((byte)0x68, "sput-wide", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SPUT_OBJECT((byte)0x69, "sput-object", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SPUT_BOOLEAN((byte)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SPUT_BYTE((byte)0x6b, "sput-byte", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SPUT_CHAR((byte)0x6c, "sput-char", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SPUT_SHORT((byte)0x6d, "sput-short", ReferenceType.field, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SGET_VOLATILE((byte)0xe5, "sget-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              //    SPUT_VOLATILE((byte)0xe6, "sput-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SGET_WIDE_VOLATILE((byte)0xea, "sget-wide-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
		//              //    SPUT_WIDE_VOLATILE((byte)0xeb, "sput-wide-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
		//              //    SGET_OBJECT_VOLATILE((byte)0xfd, "sget-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
		//              //    SPUT_OBJECT_VOLATILE((byte)0xfe, "sput-object-volatile", ReferenceType.field, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE);
		//              default:
		//                  break;
		//              }
		//              break;
		//          }
		//
		//          case Format21t: {
		//
		//              Instruction21t dInst = (Instruction21t)instruction;
		//
		//              Register oper1 = regBank.get(dInst.getRegisterA());
		//              int offset = dInst.getCodeOffset();
		//
		//              switch(dInst.opcode) {
		//              case IF_EQZ:
		//                  instructions.add(new Branch.UnaryBranch(i,
		//                          offset, Branch.UnaryBranch.CompareOp.EQZ, oper1));
		//                  break;
		//              case IF_NEZ:
		//                  instructions.add(new Branch.UnaryBranch(i,
		//                          offset, Branch.UnaryBranch.CompareOp.NEZ, oper1));
		//                  break;
		//              case IF_LTZ:
		//                  instructions.add(new Branch.UnaryBranch(i,
		//                          offset, Branch.UnaryBranch.CompareOp.LTZ, oper1));
		//                  break;
		//              case IF_GEZ:
		//                  instructions.add(new Branch.UnaryBranch(i,
		//                          offset, Branch.UnaryBranch.CompareOp.GEZ, oper1));
		//                  break;
		//              case IF_GTZ:
		//                  instructions.add(new Branch.UnaryBranch(i,
		//                          offset, Branch.UnaryBranch.CompareOp.GTZ, oper1));
		//                  break;
		//              case IF_LEZ:
		//                  instructions.add(new Branch.UnaryBranch(i,
		//                          offset, Branch.UnaryBranch.CompareOp.LEZ, oper1));
		//                  break;
		//              default:
		//                  logger.debug(instruction.opcode.name + " - " + instruction.getFormat().toString());
		//                  break;
		//              }
		//              /*
		//  IF_EQZ((byte)0x38, "if-eqz", ReferenceType.none, Format.Format21t, Opcode.CAN_CONTINUE),
		//    IF_NEZ((byte)0x39, "if-nez", ReferenceType.none, Format.Format21t, Opcode.CAN_CONTINUE),
		//    IF_LTZ((byte)0x3a, "if-ltz", ReferenceType.none, Format.Format21t, Opcode.CAN_CONTINUE),
		//    IF_GEZ((byte)0x3b, "if-gez", ReferenceType.none, Format.Format21t, Opcode.CAN_CONTINUE),
		//    IF_GTZ((byte)0x3c, "if-gtz", ReferenceType.none, Format.Format21t, Opcode.CAN_CONTINUE),
		//    IF_LEZ((byte)0x3d, "if-lez", ReferenceType.none, Format.Format21t, Opcode.CAN_CONTINUE),
		//
		//               */
		//          break;
		//          }
		//          case Format22t: {
		//              Instruction22t dInst = (Instruction22t)instruction;
		//
		//
		//              Register oper1 = regBank.get(dInst.getRegisterA());
		//              Register oper2 = regBank.get(dInst.getRegisterB());
		//              int offset = dInst.getTargetAddressOffset();
		//
		//              switch(dInst.opcode) {
		//              case IF_EQ:
		//                  instructions.add(new Branch.BinaryBranch(i, offset,
		//                          Branch.BinaryBranch.CompareOp.EQ, oper1, oper2));
		//                  break;
		//              case IF_NE:
		//                  instructions.add(new Branch.BinaryBranch(i, offset,
		//                          Branch.BinaryBranch.CompareOp.NE, oper1, oper2));
		//                  break;
		//              case IF_LT:
		//                  instructions.add(new Branch.BinaryBranch(i, offset,
		//                          Branch.BinaryBranch.CompareOp.LT, oper1, oper2));
		//                  break;
		//              case IF_GE:
		//                  instructions.add(new Branch.BinaryBranch(i, offset,
		//                          Branch.BinaryBranch.CompareOp.GE, oper1, oper2));
		//                  break;
		//              case IF_GT:
		//                  instructions.add(new Branch.BinaryBranch(i, offset,
		//                          Branch.BinaryBranch.CompareOp.GT, oper1, oper2));
		//                  break;
		//              case IF_LE:
		//                  instructions.add(new Branch.BinaryBranch(i, offset,
		//                          Branch.BinaryBranch.CompareOp.LE, oper1, oper2));
		//                  break;
		//              default:
		//                  logger.debug(instruction.opcode.name + " - " + instruction.getFormat().toString());
		//                  break;
		//              }
		///*                IF_EQ((byte)0x32, "if-eq", ReferenceType.none, Format.Format22t, Opcode.CAN_CONTINUE),
		//              IF_NE((byte)0x33, "if-ne", ReferenceType.none, Format.Format22t, Opcode.CAN_CONTINUE),
		//              IF_LT((byte)0x34, "if-lt", ReferenceType.none, Format.Format22t, Opcode.CAN_CONTINUE),
		//              IF_GE((byte)0x35, "if-ge", ReferenceType.none, Format.Format22t, Opcode.CAN_CONTINUE),
		//              IF_GT((byte)0x36, "if-gt", ReferenceType.none, Format.Format22t, Opcode.CAN_CONTINUE),
		//              IF_LE((byte)0x37, "if-le", ReferenceType.none, Format.Format22t, Opcode.CAN_CONTINUE),
		//*/
		//              break;
		//          }
		//          case Format31t: {
		//              /*    PACKED_SWITCH((byte)0x2b, "packed-switch", ReferenceType.none, Format.Format31t, Opcode.CAN_CONTINUE),
		//    SPARSE_SWITCH((byte)0x2c, "sparse-switch", ReferenceType.none, Format.Format31t, Opcode.CAN_CONTINUE),
		//*/
		//              Instruction31t dInst = (Instruction31t)instruction;
		//              Register val = regBank.get(dInst.getRegisterA());
		//              int offset = dInst.getTargetAddressOffset();
		//  //          instructions.add(new Switch(i,
		//  //                  getSparseSwitchPad(offset, codes, 3), val));
		//              break;
		//          }
		//
		//
		//
		//          case Format35c: {
		//              
		//              // = invoke virtual
		//              //iinstructions[i] = new IInstruction35c((Instruction35c)instruction, this);
		//              break;
		//          }
		//
		//
		//          default:
		//              logger.debug(instruction.opcode.name + " - " + instruction.getFormat().toString());
		//              break;
		//          }
		//
		//
		//      }
		//
		//      //comment out stop
	}

	private static TypeReference findOutArrayElementType(
			org.jf.dexlib2.iface.instruction.Instruction inst, Instruction[] walaInstructions, int instCounter) {
		if (instCounter < 0) {
			throw new IllegalArgumentException();
		} else if (instCounter == 0) {
			throw new UnsupportedOperationException("fill-array-data as first instruction is not supported!");
		}
						
		Instruction31t arrayFill = (Instruction31t)inst;
		int interestingRegister = arrayFill.getRegisterA();
		int curCounter = instCounter - 1;

		while (curCounter >= 0) {
			Instruction curInst = walaInstructions[curCounter];
			// do we have a 'new-array'-instruction, where the destination register coincides with the current interesting register?
			// then we return the element type of that array
			if (curInst.getOpcode() == Opcode.NEW_ARRAY) {
				NewArray newArray = (NewArray) walaInstructions[curCounter];
				if (newArray.destination == interestingRegister) {
					return newArray.newSiteRef.getDeclaredType().getArrayElementType();
				}
			} else if (curInst.getOpcode() == Opcode.MOVE_OBJECT || curInst.getOpcode() == Opcode.MOVE_OBJECT_16 || curInst.getOpcode() == Opcode.MOVE_OBJECT_FROM16) {
                UnaryOperation uo = (UnaryOperation) curInst;

                if (uo.destination == interestingRegister) {
                    interestingRegister = uo.source;
                }
			}
			// all other instructions are ignored
			curCounter--;
		}

		throw new UnsupportedOperationException("found a fill-array-data instruction without a corresponding new-array instruction. This should not happen!");
	}

	protected void handleINVOKE_VIRTUAL(int instLoc, String cname, String mname, String pname, int[] args, Opcode opcode ) {
		instructions.add(new Invoke.InvokeVirtual(instLoc, cname, mname, pname, args, opcode, this));
	}

	public Instruction[] getDexInstructions() {
		return instructions().toArray(new Instruction[0]);
	}



	protected InstructionArray instructions(){
		if (instructions == null)
			parseBytecode();
		return instructions;
	}

	public int getAddressFromIndex(int index) {
		return instructions().getPcFromIndex(index);
	}

	@Override
	public int getInstructionIndex(int bytecodeindex) {
		return instructions().getIndexFromPc(bytecodeindex);
	}

	public Instruction getInstructionFromIndex(int instructionIndex) {
		return instructions().getFromId(instructionIndex);
	}

	private static final IndirectionData NO_INDIRECTIONS = new IndirectionData() {

		private final int[] NOTHING = new int[0];

		@Override
		public int[] indirectlyReadLocals(int instructionIndex) {
			return NOTHING;
		}

		@Override
		public int[] indirectlyWrittenLocals(int instructionIndex) {
			return NOTHING;
		}

	};


	@Override
	public IndirectionData getIndirectionData() {
		return NO_INDIRECTIONS;
	}

	//-------------------------------------------
	// MethodAnnotationIteratorDelegate Methods
	//-------------------------------------------


//	/**
//	 * Delegate called by the class in order to parse the method annotations.
//	 */
//	public void processMethodAnnotations(MethodIdItem mIdItem,
//			AnnotationSetItem anoSet) {
//		//System.out.println("DexIMethod: processMethodAnnotations()");
//		if ( mIdItem.equals(eMethod.method) ){
//			AnnotationItem[] items = anoSet.getAnnotations();
//			for (AnnotationItem item : items) {
//				
//			}
//
//		}
//	}

    /**
     *
     * @throws UnsupportedOperationException
     *
     * TODO: Review this implementation - it may be horribly wrong!
     */
	@Override
	public Collection<CallSiteReference> getCallSites() {
        if (isNative()) {
            return Collections.emptySet();
        }

        // assert(false) : "Please review getCallSites-Implementation before use!";        // TODO

        ArrayList<CallSiteReference> csites = new ArrayList<>();
        // XXX The call Sites in this method or to this method?!!!
        for (Instruction inst: instructions()) {
            if (inst instanceof Invoke) {
                // Locate the Target
            	MethodReference target = MethodReference.findOrCreate(
                    getDeclaringClass().getClassLoader().getReference(),    // XXX: Is this the correct class loader?
                    ((Invoke)inst).clazzName,
                    ((Invoke)inst).methodName,
                    ((Invoke)inst).descriptor );

                csites.add(
                    CallSiteReference.make(
                        inst.pc,    // programCounter
                        target,     // declaredTarget
                        ((Invoke)inst).getInvocationCode() // invocationCode
                        ));
            }
        }
        return Collections.unmodifiableCollection(csites);
	}

	@Override
	public SourcePosition getSourcePosition(int instructionIndex) {
		return null;
	}

	@Override
	public SourcePosition getParameterSourcePosition(int paramNum) {
		return null;
	}

	@Override
	public Collection<Annotation> getAnnotations() {
		return myClass.getAnnotations(eMethod, null);
	}

	@Override
	public Collection<Annotation> getAnnotations(boolean runtimeInvisible) {
		return myClass.getAnnotations(eMethod, DexIClass.getTypes(runtimeInvisible));
	}

	@Override
	public Collection<Annotation>[] getParameterAnnotations() {
		Map<Integer, List<Annotation>> raw = myClass.getParameterAnnotations(eMethod);
		@SuppressWarnings("unchecked")
		Collection<Annotation>[] result = new Collection[ getReference().getNumberOfParameters() ];
		for(Map.Entry<Integer, List<Annotation>> x : raw.entrySet()) {
			result[x.getKey()] = x.getValue();
		}
		return result;
	}

	
}
