pxb.android.dex2jar.v3.V3CodeAdapter.java Source code

Java tutorial

Introduction

Here is the source code for pxb.android.dex2jar.v3.V3CodeAdapter.java

Source

/*
 * Copyright (c) 2009-2010 Panxiaobo
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package pxb.android.dex2jar.v3;

import java.util.HashMap;
import java.util.Map;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import pxb.android.dex2jar.DexOpcodeDump;
import pxb.android.dex2jar.DexOpcodeUtil;
import pxb.android.dex2jar.DexOpcodes;
import pxb.android.dex2jar.Field;
import pxb.android.dex2jar.Method;
import pxb.android.dex2jar.visitors.DexCodeVisitor;

/**
 * @author Panxiaobo [pxb1988@126.com]
 * @version $Id$
 */
public class V3CodeAdapter implements DexCodeVisitor, Opcodes, DexOpcodes {
    private MethodVisitor mv;
    private int _regcount = 0;
    private Map<Integer, Integer> map = new HashMap<Integer, Integer>();
    private int maxStack = 0;
    private Map<Label, Type> handlers = new HashMap<Label, Type>();

    /**
     * ?
     */
    private static final int TEMP_REG = Integer.MAX_VALUE;

    private void stack(int a) {
        if (a > maxStack) {
            maxStack = a;
        }
    }

    /**
     * ??
     * 
     * @param reg
     * @return
     */
    private int map(int reg) {
        Integer integer = map.get(reg);
        if (integer == null) {
            integer = _regcount++;
            map.put(reg, integer);
        }
        return integer;
    }

    /**
     * @param mv
     */
    public V3CodeAdapter(MethodVisitor mv) {
        super();
        this.mv = mv;
    }

    public void visitInitLocal(int... args) {
        for (int i : args) {
            map(i);
        }
        map(TEMP_REG);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitArrayInsn(int, int, int, int)
     */
    public void visitArrayInsn(int opcode, int regFromOrTo, int array, int index) {
        checkResult();
        switch (opcode) {
        case OP_APUT: // int
        case OP_APUT_BOOLEAN:
        case OP_APUT_BYTE:
        case OP_APUT_CHAR:
        case OP_APUT_SHORT: {
            mv.visitVarInsn(ALOAD, map(array));
            mv.visitVarInsn(ILOAD, map(index));
            mv.visitVarInsn(ILOAD, map(regFromOrTo));
            mv.visitInsn(DexOpcodeUtil.mapOpcode(opcode));
            stack(3);
        }
            break;
        case OP_APUT_WIDE: // long
        {
            mv.visitVarInsn(ALOAD, map(array));
            mv.visitVarInsn(ILOAD, map(index));
            mv.visitVarInsn(LLOAD, map(regFromOrTo));
            mv.visitInsn(LASTORE);
            stack(3);
        }
            break;
        case OP_APUT_OBJECT: {
            mv.visitVarInsn(ALOAD, map(array));
            mv.visitVarInsn(ILOAD, map(index));
            mv.visitVarInsn(ALOAD, map(regFromOrTo));
            mv.visitInsn(AASTORE);
            stack(3);
        }
            break;
        case OP_AGET:
        case OP_AGET_BOOLEAN:
        case OP_AGET_BYTE:
        case OP_AGET_CHAR:
        case OP_AGET_SHORT: {
            mv.visitVarInsn(ALOAD, map(array));
            mv.visitVarInsn(ILOAD, map(index));
            mv.visitInsn(DexOpcodeUtil.mapOpcode(opcode));
            mv.visitVarInsn(ISTORE, map(regFromOrTo));
            stack(2);
        }
            break;
        case OP_AGET_WIDE: {
            mv.visitVarInsn(ALOAD, map(array));
            mv.visitVarInsn(ILOAD, map(index));
            mv.visitInsn(LALOAD);
            mv.visitVarInsn(LSTORE, map(regFromOrTo));
            stack(2);
        }
            break;
        case OP_AGET_OBJECT: {
            mv.visitVarInsn(ALOAD, map(array));
            mv.visitVarInsn(ILOAD, map(index));
            mv.visitInsn(AALOAD);
            mv.visitVarInsn(ASTORE, map(regFromOrTo));
            stack(2);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitArrayInsn(int, java.lang.String, int, int)
     */
    public void visitArrayInsn(int opcode, String type, int saveToReg, int demReg) {
        checkResult();
        switch (opcode) {
        case OP_NEW_ARRAY: {
            mv.visitVarInsn(ILOAD, map(demReg));
            int shortType = Type.getType(type).getElementType().getSort();
            switch (shortType) {
            case Type.BOOLEAN:
                mv.visitIntInsn(NEWARRAY, T_BOOLEAN);
                break;
            case Type.BYTE:
                mv.visitIntInsn(NEWARRAY, T_BYTE);
                break;
            case Type.CHAR:
                mv.visitIntInsn(NEWARRAY, T_CHAR);
                break;
            case Type.DOUBLE:
                mv.visitIntInsn(NEWARRAY, T_DOUBLE);
                break;
            case Type.FLOAT:
                mv.visitIntInsn(NEWARRAY, T_FLOAT);
                break;
            case Type.INT:
                mv.visitIntInsn(NEWARRAY, T_INT);
                break;
            case Type.OBJECT:
                mv.visitTypeInsn(ANEWARRAY, type);
                break;
            }
            mv.visitVarInsn(ASTORE, map(saveToReg));
            stack(2);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitEnd()
     */
    public void visitEnd() {
        checkResult();
        mv.visitMaxs(this.maxStack, this._regcount);
        mv.visitEnd();
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitFieldInsn(int, pxb.android.dex2jar.Field, int, int)
     */
    public void visitFieldInsn(int opcode, Field field, int regFromOrTo, int ownerReg) {
        checkResult();
        switch (opcode) {
        case OP_IGET:
        case OP_IGET_WIDE:
        case OP_IGET_OBJECT:
        case OP_IGET_BOOLEAN:
        case OP_IGET_BYTE:
        case OP_IGET_CHAR:
        case OP_IGET_SHORT:
        //
        {
            mv.visitVarInsn(ALOAD, map(ownerReg));
            mv.visitFieldInsn(GETFIELD, field.getOwner(), field.getName(), field.getType());
            switch (opcode) {
            case OP_IGET:
            case OP_IGET_BOOLEAN:
            case OP_IGET_BYTE:
            case OP_IGET_CHAR:
            case OP_IGET_SHORT:
                mv.visitVarInsn(ISTORE, map(regFromOrTo));
                break;
            case OP_IGET_WIDE:
                mv.visitVarInsn(LSTORE, map(regFromOrTo));
                break;
            case OP_IGET_OBJECT:
                mv.visitVarInsn(ASTORE, map(regFromOrTo));
                break;
            }
            stack(1);
        }
            break;

        case OP_IPUT:
        case OP_IPUT_WIDE:
        case OP_IPUT_OBJECT:
        case OP_IPUT_BOOLEAN:
        case OP_IPUT_BYTE:
        case OP_IPUT_CHAR:
        case OP_IPUT_SHORT: {
            mv.visitVarInsn(ALOAD, map(ownerReg));
            switch (opcode) {
            case OP_IPUT:
            case OP_IPUT_BOOLEAN:
            case OP_IPUT_BYTE:
            case OP_IPUT_CHAR:
            case OP_IPUT_SHORT:
                mv.visitVarInsn(ILOAD, map(regFromOrTo));
                break;
            case OP_IPUT_WIDE:
                mv.visitVarInsn(LLOAD, map(regFromOrTo));
                break;
            case OP_IPUT_OBJECT:
                mv.visitVarInsn(ALOAD, map(regFromOrTo));
                break;
            }
            stack(2);
            mv.visitFieldInsn(PUTFIELD, field.getOwner(), field.getName(), field.getType());
        }
            break;
        case OP_SPUT_OBJECT:
        case OP_SPUT:
        case OP_SPUT_WIDE:
        case OP_SPUT_BOOLEAN:
        case OP_SPUT_BYTE:
        case OP_SPUT_CHAR:
        case OP_SPUT_SHORT:
            switch (opcode) {
            case OP_SPUT_OBJECT:
                mv.visitVarInsn(ALOAD, map(regFromOrTo));
                break;
            case OP_SPUT:
            case OP_SPUT_BOOLEAN:
            case OP_SPUT_BYTE:
            case OP_SPUT_CHAR:
            case OP_SPUT_SHORT:
                mv.visitVarInsn(ILOAD, map(regFromOrTo));
                break;
            case OP_SPUT_WIDE:
                mv.visitVarInsn(LLOAD, map(regFromOrTo));
                break;
            }
            mv.visitFieldInsn(PUTSTATIC, field.getOwner(), field.getName(), field.getType());
            stack(1);
            break;
        case OP_SGET_OBJECT:// sget-object
        case OP_SGET:
        case OP_SGET_WIDE:
        case OP_SGET_BOOLEAN:
        case OP_SGET_BYTE:
        case OP_SGET_CHAR:
        case OP_SGET_SHORT: {
            mv.visitFieldInsn(GETSTATIC, field.getOwner(), field.getName(), field.getType());
            switch (opcode) {
            case OP_SGET_OBJECT:// sget-object
                mv.visitVarInsn(ASTORE, map(regFromOrTo));
                break;
            case OP_SGET_WIDE:
                mv.visitVarInsn(LSTORE, map(regFromOrTo));
                break;
            case OP_SGET:
            case OP_SGET_BOOLEAN:
            case OP_SGET_BYTE:
            case OP_SGET_CHAR:
            case OP_SGET_SHORT:
                mv.visitVarInsn(ISTORE, map(regFromOrTo));
                break;
            }
            stack(1);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));

        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitFillArrayInsn(int, int, int, int, java.lang.Object[])
     */
    public void visitFillArrayInsn(int opcode, int reg, int elemWidth, int initLength, Object[] values) {
        checkResult();
        int op = 0;
        switch (elemWidth) {
        case 1:
            op = BASTORE;
            break;
        case 2:
            op = SASTORE;
            break;
        case 4:
            op = IASTORE;
            break;
        case 8:
            op = LASTORE;
            break;
        }
        mv.visitVarInsn(ALOAD, map(reg));
        for (int i = 0; i < initLength; i++) {
            mv.visitInsn(DUP);
            mv.visitLdcInsn(i);
            mv.visitLdcInsn(values[i]);
            mv.visitInsn(op);
        }
        mv.visitVarInsn(ASTORE, map(reg));
        stack(4);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitFilledNewArrayIns(int, java.lang.String, int[])
     */
    public void visitFilledNewArrayIns(int opcode, String type, int[] regs) {
        checkResult();
        Type elem = Type.getType(type).getElementType();
        int shortType = elem.getSort();
        mv.visitLdcInsn(regs.length);
        switch (shortType) {
        case Type.BOOLEAN:
            mv.visitIntInsn(NEWARRAY, T_BOOLEAN);
            break;
        case Type.BYTE:
            mv.visitIntInsn(NEWARRAY, T_BYTE);
            break;
        case Type.CHAR:
            mv.visitIntInsn(NEWARRAY, T_CHAR);
            break;
        case Type.DOUBLE:
            mv.visitIntInsn(NEWARRAY, T_DOUBLE);
            break;
        case Type.FLOAT:
            mv.visitIntInsn(NEWARRAY, T_FLOAT);
            break;
        case Type.INT:
            mv.visitIntInsn(NEWARRAY, T_INT);
            break;
        case Type.OBJECT:
            mv.visitTypeInsn(ANEWARRAY, type);
            break;
        }
        int store = elem.getOpcode(IASTORE);
        int load = elem.getOpcode(ILOAD);
        for (int i = 0; i < regs.length; i++) {
            mv.visitInsn(DUP);
            mv.visitLdcInsn(i);
            mv.visitVarInsn(load, map(regs[i]));
            mv.visitInsn(store);
        }
        mv.visitVarInsn(ASTORE, map(TEMP_REG));
        stack(4);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitInInsn(int, int, int)
     */
    public void visitInInsn(int opcode, int saveToReg, int opReg) {
        checkResult();
        switch (opcode) {
        case OP_AND_INT_2ADDR:
        case OP_AND_LONG_2ADDR:
        case OP_OR_INT_2ADDR:
        case OP_OR_LONG_2ADDR:
        case OP_XOR_INT_2ADDR:
        case OP_XOR_LONG_2ADDR:
        case OP_SUB_DOUBLE_2ADDR:
        case OP_SUB_FLOAT_2ADDR:
        case OP_SUB_INT_2ADDR:
        case OP_SUB_LONG_2ADDR:
        case OP_MUL_LONG_2ADDR:
        case OP_MUL_INT_2ADDR:
        case OP_MUL_FLOAT_2ADDR:
        case OP_MUL_DOUBLE_2ADDR:
        case OP_REM_LONG_2ADDR:
        case OP_REM_INT_2ADDR:
        case OP_REM_DOUBLE_2ADDR:
        case OP_REM_FLOAT_2ADDR:
        case OP_DIV_INT_2ADDR:
        case OP_DIV_LONG_2ADDR:
        case OP_DIV_FLOAT_2ADDR:
        case OP_DIV_DOUBLE_2ADDR:
        case OP_ADD_INT_2ADDR:
        case OP_ADD_LONG_2ADDR:
        case OP_ADD_FLOAT_2ADDR:
        case OP_ADD_DOUBLE_2ADDR:
        case OP_SHR_LONG_2ADDR:
        case OP_SHL_LONG_2ADDR:
        case OP_USHR_LONG_2ADDR:
        case OP_SHR_INT_2ADDR:
        case OP_SHL_INT_2ADDR:
        case OP_USHR_INT_2ADDR: {
            int load = 0;
            int store = 0;
            switch (opcode) {
            case OP_AND_INT_2ADDR:
            case OP_SUB_INT_2ADDR:
            case OP_OR_INT_2ADDR:
            case OP_MUL_INT_2ADDR:
            case OP_XOR_INT_2ADDR:
            case OP_ADD_INT_2ADDR:
            case OP_REM_INT_2ADDR:
            case OP_DIV_INT_2ADDR:
            case OP_SHR_INT_2ADDR:
            case OP_SHL_INT_2ADDR:
            case OP_USHR_INT_2ADDR: {
                load = ILOAD;
                store = ISTORE;
            }
                break;
            case OP_SUB_LONG_2ADDR:
            case OP_MUL_LONG_2ADDR:
            case OP_ADD_LONG_2ADDR:
            case OP_AND_LONG_2ADDR:
            case OP_OR_LONG_2ADDR:
            case OP_XOR_LONG_2ADDR:
            case OP_REM_LONG_2ADDR:
            case OP_DIV_LONG_2ADDR:
            case OP_SHR_LONG_2ADDR:
            case OP_SHL_LONG_2ADDR:
            case OP_USHR_LONG_2ADDR: {
                load = LLOAD;
                store = LSTORE;
            }
                break;
            case OP_SUB_FLOAT_2ADDR:
            case OP_ADD_FLOAT_2ADDR:
            case OP_DIV_FLOAT_2ADDR:
            case OP_MUL_FLOAT_2ADDR:
            case OP_REM_FLOAT_2ADDR: {
                load = FLOAD;
                store = FSTORE;
            }
                break;
            case OP_DIV_DOUBLE_2ADDR:
            case OP_SUB_DOUBLE_2ADDR:
            case OP_ADD_DOUBLE_2ADDR:
            case OP_MUL_DOUBLE_2ADDR:
            case OP_REM_DOUBLE_2ADDR: {
                load = DLOAD;
                store = DSTORE;
            }
                break;
            }
            mv.visitVarInsn(load, map(saveToReg));
            mv.visitVarInsn(load, map(opReg));
            mv.visitInsn(DexOpcodeUtil.mapOpcode(opcode));
            mv.visitVarInsn(store, map(saveToReg));
            stack(2);
        }
            break;
        case OP_NEG_INT:
        case OP_NEG_DOUBLE:
        case OP_NEG_FLOAT:
        case OP_NEG_LONG:
        case OP_INT_TO_BYTE:
        case OP_INT_TO_SHORT:
        case OP_INT_TO_CHAR:
        case OP_INT_TO_FLOAT:
        case OP_INT_TO_DOUBLE:
        case OP_INT_TO_LONG:
        case OP_LONG_TO_DOUBLE:
        case OP_LONG_TO_FLOAT:
        case OP_LONG_TO_INT:
        case OP_DOUBLE_TO_FLOAT:
        case OP_DOUBLE_TO_INT:
        case OP_DOUBLE_TO_LONG:
        case OP_FLOAT_TO_INT:
        case OP_FLOAT_TO_LONG:
        case OP_FLOAT_TO_DOUBLE:
        case OP_ARRAY_LENGTH: {
            int load = 0;
            int store = 0;
            switch (opcode) {
            case OP_NEG_INT: {
                load = ILOAD;
                store = ISTORE;
            }
                break;
            case OP_NEG_DOUBLE: {
                load = DLOAD;
                store = ISTORE;
            }
                break;
            case OP_NEG_FLOAT: {
                load = FLOAD;
                store = ISTORE;
            }
                break;
            case OP_NEG_LONG: {
                load = LLOAD;
                store = ISTORE;
            }
                break;
            case OP_INT_TO_BYTE: {
                load = ILOAD;
                store = ISTORE;
            }
                break;
            case OP_INT_TO_SHORT: {
                load = ILOAD;
                store = ISTORE;
            }
                break;
            case OP_INT_TO_CHAR: {
                load = ILOAD;
                store = ISTORE;
            }
                break;
            case OP_INT_TO_FLOAT: {
                load = ILOAD;
                store = FSTORE;
            }
                break;
            case OP_INT_TO_DOUBLE: {
                load = ILOAD;
                store = DSTORE;
            }
                break;
            case OP_INT_TO_LONG: {
                load = ILOAD;
                store = LSTORE;
            }
                break;
            case OP_LONG_TO_DOUBLE: {
                load = LLOAD;
                store = DSTORE;
            }
                break;
            case OP_LONG_TO_FLOAT: {
                load = LLOAD;
                store = FSTORE;
            }
                break;
            case OP_LONG_TO_INT: {
                load = LLOAD;
                store = ISTORE;
            }
                break;
            case OP_DOUBLE_TO_FLOAT: {
                load = DLOAD;
                store = FSTORE;
            }
                break;
            case OP_DOUBLE_TO_INT: {
                load = DLOAD;
                store = ISTORE;
            }
                break;
            case OP_DOUBLE_TO_LONG: {
                load = DLOAD;
                store = LSTORE;
            }
                break;
            case OP_FLOAT_TO_INT: {
                load = FLOAD;
                store = ISTORE;
            }
                break;
            case OP_FLOAT_TO_LONG: {
                load = FLOAD;
                store = LSTORE;
            }
                break;
            case OP_FLOAT_TO_DOUBLE: {
                load = FLOAD;
                store = DSTORE;
            }
                break;
            case OP_ARRAY_LENGTH: {
                load = ALOAD;
                store = ISTORE;
            }
                break;
            }
            mv.visitVarInsn(load, map(opReg));
            mv.visitInsn(DexOpcodeUtil.mapOpcode(opcode));
            mv.visitVarInsn(store, map(saveToReg));
            stack(1);
        }
            break;
        case OP_MOVE_OBJECT:
        case OP_MOVE_OBJECT_FROM16:
        case OP_MOVE:
        case OP_MOVE_WIDE:
        case OP_MOVE_FROM16:
        case OP_MOVE_WIDE_FROM16: {
            int load = 0;
            int store = 0;
            switch (opcode) {
            case OP_MOVE_OBJECT:
            case OP_MOVE_OBJECT_FROM16: {
                load = ALOAD;
                store = ASTORE;
            }
                break;
            case OP_MOVE:
            case OP_MOVE_FROM16: {
                load = ILOAD;
                store = ISTORE;
            }
                break;
            case OP_MOVE_WIDE:
            case OP_MOVE_WIDE_FROM16: {
                load = LLOAD;
                store = LSTORE;
            }
                break;
            }
            mv.visitVarInsn(load, map(opReg));
            mv.visitVarInsn(store, map(saveToReg));
            stack(1);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));

        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitInInsn(int, int, int, int)
     */
    public void visitInInsn(int opcode, int saveToReg, int opReg, int opValueOrReg) {
        checkResult();
        switch (opcode) {
        case OP_USHR_INT_LIT8:
        case OP_SHR_INT_LIT8:
        case OP_SHL_INT_LIT8:
        case OP_ADD_INT_LIT8:
        case OP_REM_INT_LIT8:
        case OP_AND_INT_LIT8:
        case OP_OR_INT_LIT8:
        case OP_XOR_INT_LIT8:
        case OP_DIV_INT_LIT8:
        case OP_MUL_INT_LIT8: {
            mv.visitVarInsn(ILOAD, map(opReg));
            mv.visitLdcInsn(opValueOrReg);
            mv.visitInsn(DexOpcodeUtil.mapOpcode(opcode));
            mv.visitVarInsn(ISTORE, map(saveToReg));
            stack(2);
        }
            break;

        case OP_AND_LONG:
        case OP_AND_INT:
        case OP_OR_LONG:
        case OP_OR_INT:
        case OP_XOR_LONG:
        case OP_XOR_INT:
        case OP_ADD_INT:
        case OP_ADD_LONG:
        case OP_ADD_FLOAT:
        case OP_ADD_DOUBLE:
        case OP_SUB_FLOAT:
        case OP_SUB_DOUBLE:
        case OP_SUB_INT:
        case OP_SUB_LONG:
        case OP_DIV_INT:
        case OP_DIV_LONG:
        case OP_DIV_FLOAT:
        case OP_DIV_DOUBLE:
        case OP_MUL_INT:
        case OP_MUL_LONG:
        case OP_MUL_FLOAT:
        case OP_MUL_DOUBLE:
        case OP_CMP_LONG:
        case OP_REM_LONG:
        case OP_REM_INT:
        case OP_REM_FLOAT:
        case OP_REM_DOUBLE:
        case OP_CMPL_DOUBLE:
        case OP_CMPG_DOUBLE:
        case OP_CMPL_FLOAT:
        case OP_CMPG_FLOAT:
        case OP_SHR_INT:
        case OP_SHL_INT:
        case OP_USHR_INT:
        case OP_SHR_LONG:
        case OP_SHL_LONG:
        case OP_USHR_LONG: {
            int load = 0;
            int store = 0;
            switch (opcode) {

            case OP_AND_INT:
            case OP_OR_INT:
            case OP_XOR_INT:
            case OP_SUB_INT:
            case OP_DIV_INT:
            case OP_MUL_INT:
            case OP_REM_INT:
            case OP_ADD_INT:
            case OP_SHR_INT:
            case OP_SHL_INT:
            case OP_USHR_INT: {
                load = ILOAD;
                store = ISTORE;
            }
                break;

            case OP_OR_LONG:
            case OP_AND_LONG:
            case OP_XOR_LONG:
            case OP_ADD_LONG:
            case OP_SUB_LONG:
            case OP_MUL_LONG:
            case OP_CMP_LONG:
            case OP_REM_LONG:
            case OP_DIV_LONG:
            case OP_SHR_LONG:
            case OP_SHL_LONG:
            case OP_USHR_LONG: {
                load = LLOAD;
                store = LSTORE;
            }
                break;
            case OP_ADD_FLOAT:
            case OP_SUB_FLOAT:
            case OP_DIV_FLOAT:
            case OP_MUL_FLOAT:
            case OP_REM_FLOAT:
            case OP_CMPL_FLOAT:
            case OP_CMPG_FLOAT: {
                load = FLOAD;
                store = FSTORE;
            }
                break;
            case OP_ADD_DOUBLE:
            case OP_SUB_DOUBLE:
            case OP_DIV_DOUBLE:
            case OP_MUL_DOUBLE:
            case OP_REM_DOUBLE:
            case OP_CMPL_DOUBLE:
            case OP_CMPG_DOUBLE: {
                load = DLOAD;
                store = DSTORE;
            }
                break;

            }
            mv.visitVarInsn(load, map(opValueOrReg));
            mv.visitVarInsn(load, map(opReg));
            mv.visitInsn(DexOpcodeUtil.mapOpcode(opcode));
            mv.visitVarInsn(store, map(saveToReg));
            stack(2);
        }
            break;

        case OP_MUL_INT_LIT16:
        case OP_DIV_INT_LIT16:
        case OP_REM_INT_LIT16:
        case OP_ADD_INT_LIT16:
        case OP_AND_INT_LIT16:
        case OP_OR_INT_LIT16:
        case OP_XOR_INT_LIT16: {
            mv.visitVarInsn(ILOAD, map(opReg));
            mv.visitLdcInsn(opValueOrReg);
            mv.visitInsn(DexOpcodeUtil.mapOpcode(opcode));
            mv.visitVarInsn(ISTORE, map(saveToReg));
            stack(2);
        }
            break;

        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));

        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitInsn(int)
     */
    public void visitInsn(int opcode) {
        checkResult();
        switch (opcode) {
        case OP_RETURN_VOID: {
            mv.visitInsn(RETURN);
        }
            break;
        case OP_CONST_4:
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitJumpInsn(int, int)
     */
    public void visitJumpInsn(int opcode, Label label) {
        checkResult();
        switch (opcode) {
        case OP_GOTO:
        case OP_GOTO_16: {
            mv.visitJumpInsn(GOTO, label);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));

        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitJumpInsn(int, int, int)
     */
    public void visitJumpInsn(int opcode, Label label, int reg) {
        checkResult();
        mv.visitVarInsn(ILOAD, map(reg));
        stack(1);
        switch (opcode) {
        case OP_IF_NEZ: {
            mv.visitJumpInsn(IFNE, label);
        }
            break;
        case OP_IF_EQZ: {
            mv.visitJumpInsn(IFEQ, label);
        }
            break;
        case OP_IF_GTZ: {
            mv.visitJumpInsn(IFGT, label);
        }
            break;
        case OP_IF_GEZ: {
            mv.visitJumpInsn(IFGE, label);
        }
            break;
        case OP_IF_LEZ: {
            mv.visitJumpInsn(IFLE, label);
        }
            break;
        case OP_IF_LTZ: {
            mv.visitJumpInsn(IFLT, label);
        }
            break;

        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitJumpInsn(int, int, int, int)
     */
    public void visitJumpInsn(int opcode, Label label, int reg1, int reg2) {
        checkResult();
        mv.visitVarInsn(ILOAD, map(reg1));
        mv.visitVarInsn(ILOAD, map(reg2));
        mv.visitJumpInsn(DexOpcodeUtil.mapOpcode(opcode), label);
        stack(2);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitLabel(int)
     */
    public void visitLabel(Label label) {
        checkResult();
        mv.visitLabel(label);
        if (handlers.containsKey(label)) {
            // typeInStack = handlers.get(label);
            // mv.visitVarInsn(ISTORE, map(TEMP_REG));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitLdcInsn(int, java.lang.Object, int)
     */
    public void visitLdcInsn(int opcode, Object value, int reg) {
        checkResult();
        switch (opcode) {
        case OP_CONST_STRING:
        case OP_CONST_CLASS: {
            mv.visitLdcInsn(value);
            mv.visitVarInsn(ASTORE, map(reg));
            stack(1);
        }
            break;
        case OP_CONST:
        case OP_CONST_4:
        case OP_CONST_16:
        case OP_CONST_HIGH16: {
            mv.visitLdcInsn(value);
            mv.visitVarInsn(ISTORE, map(reg));
            stack(1);
        }
            break;
        case OP_CONST_WIDE:
        case OP_CONST_WIDE_16:
        case OP_CONST_WIDE_32:
        case OP_CONST_WIDE_HIGH16: {
            mv.visitLdcInsn(value);
            mv.visitVarInsn(LSTORE, map(reg));
            stack(1);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));

        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitLineNumber(int, int)
     */
    public void visitLineNumber(int line, Label label) {
        mv.visitLineNumber(line, label);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitLocalVariable(java.lang .String, java.lang.String,
     * java.lang.String, int, int, int)
     */
    public void visitLocalVariable(String name, String type, String signature, Label start, Label end, int reg) {
        mv.visitLocalVariable(name, type, signature, start, end, map(reg));
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitLookupSwitchInsn(int, int, int, int[], int[])
     */
    public void visitLookupSwitchInsn(int opcode, int reg, Label defaultOffset, int[] cases, Label[] labels) {
        checkResult();
        switch (opcode) {
        case OP_SPARSE_SWITCH:
            mv.visitVarInsn(ILOAD, map(reg));
            mv.visitLookupSwitchInsn(defaultOffset, cases, labels);
            stack(1);
            break;
        }
    }

    private void loadArgument(Method method, int[] registers, boolean isStatic) {
        int i = 0;
        if (!isStatic) {
            mv.visitVarInsn(ALOAD, map(registers[i++]));
        }
        for (String s : method.getType().getParameterTypes()) {
            mv.visitVarInsn(Type.getType(s).getOpcode(ILOAD), map(registers[i++]));
        }
        stack(registers.length);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitMethodInsn(int, pxb.android.dex2jar.Method, int[])
     */
    public void visitMethodInsn(int opcode, Method method, int[] args) {
        checkResult();

        switch (opcode) {
        case OP_INVOKE_STATIC: {
            stack(args.length);
            loadArgument(method, args, true);
            mv.visitMethodInsn(INVOKESTATIC, method.getOwner(), method.getName(), method.getType().getDesc());
        }
            break;
        default:
            stack(1 + args.length);
            loadArgument(method, args, false);
            switch (opcode) {
            case OP_INVOKE_DIRECT:
            case OP_INVOKE_SUPER: {
                mv.visitMethodInsn(INVOKESPECIAL, method.getOwner(), method.getName(), method.getType().getDesc());
            }
                break;
            case OP_INVOKE_VIRTUAL: {
                mv.visitMethodInsn(INVOKEVIRTUAL, method.getOwner(), method.getName(), method.getType().getDesc());
            }
                break;
            case OP_INVOKE_INTERFACE: {
                mv.visitMethodInsn(INVOKEINTERFACE, method.getOwner(), method.getName(),
                        method.getType().getDesc());
            }
                break;

            default:
                throw new RuntimeException(
                        String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));
            }
        }
        Type ret = Type.getType(method.getType().getReturnType());

        if (!Type.VOID_TYPE.equals(ret)) {
            mv.visitVarInsn(ISTORE, map(TEMP_REG));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitTableSwitchInsn(int, int, int, int, int, int[])
     */
    public void visitTableSwitchInsn(int opcode, int reg, int first_case, int last_case, Label default_label,
            Label[] labels) {
        checkResult();
        switch (opcode) {
        case OP_PACKED_SWITCH:
            mv.visitVarInsn(ILOAD, map(reg));
            mv.visitTableSwitchInsn(first_case, last_case, default_label, labels);
            stack(1);
            break;
        }
    }

    private void checkResult() {
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitTryCatch(int, int, int, java.lang.String)
     */
    public void visitTryCatch(Label start, Label end, Label handler, String type) {
        mv.visitTryCatchBlock(start, end, handler, type);
        if (type == null) {
            type = Type.getDescriptor(Throwable.class);
        }
        handlers.put(handler, Type.getType(type));
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitTypeInsn(int, java.lang.String, int)
     */
    public void visitTypeInsn(int opcode, String type, int toReg) {
        checkResult();
        switch (opcode) {
        case OP_NEW_INSTANCE:// new-instance
        {
            mv.visitTypeInsn(NEW, type);
            mv.visitVarInsn(ASTORE, map(toReg));
            stack(1);
        }
            break;
        case OP_CONST_CLASS:// const-class
        {
            mv.visitLdcInsn(Type.getType(type));
            mv.visitVarInsn(ASTORE, map(toReg));
            stack(1);
        }
            break;
        case OP_CHECK_CAST: {
            mv.visitVarInsn(ALOAD, map(toReg));
            mv.visitTypeInsn(CHECKCAST, type);
            mv.visitVarInsn(ASTORE, map(toReg));
            stack(1);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitTypeInsn(int, java.lang.String, int, int)
     */
    public void visitTypeInsn(int opcode, String type, int toReg, int fromReg) {
        checkResult();
        switch (opcode) {
        case OP_INSTANCE_OF: {
            mv.visitVarInsn(ALOAD, map(fromReg));
            mv.visitTypeInsn(INSTANCEOF, type);
            mv.visitVarInsn(ISTORE, map(toReg));
            stack(1);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pxb.android.dex2jar.visitors.DexCodeVisitor#visitVarInsn(int, int)
     */
    public void visitVarInsn(int opcode, int reg) {
        switch (opcode) {
        case OP_MOVE_RESULT_OBJECT:// move-result-object
        case OP_MOVE_RESULT:
        case OP_MOVE_EXCEPTION:
        case OP_MOVE_RESULT_WIDE:
            break;
        default:
            checkResult();
        }

        switch (opcode) {
        case OP_MOVE_RESULT_OBJECT:// move-result-object
        case OP_MOVE_RESULT:
        case OP_MOVE_RESULT_WIDE:
        //
        {
            mv.visitVarInsn(ILOAD, map(TEMP_REG));
            mv.visitVarInsn(ISTORE, map(reg));
            stack(1);
        }
            break;
        case OP_MOVE_EXCEPTION:
            mv.visitVarInsn(ASTORE, map(reg));
            stack(1);
            break;
        case OP_THROW:// throw
        {
            mv.visitVarInsn(ALOAD, map(reg));
            mv.visitInsn(ATHROW);
            stack(1);
        }
            break;
        case OP_RETURN: {
            mv.visitVarInsn(ILOAD, map(reg));
            mv.visitInsn(IRETURN);
            stack(1);
        }
            break;
        case OP_RETURN_OBJECT: {
            mv.visitVarInsn(ALOAD, map(reg));
            mv.visitInsn(ARETURN);
            stack(1);
        }
            break;
        case OP_RETURN_WIDE:
        //
        {
            mv.visitVarInsn(LLOAD, map(reg));
            mv.visitInsn(LRETURN);
            stack(1);
        }
            break;
        case OP_MONITOR_ENTER: {
            mv.visitVarInsn(ALOAD, map(reg));
            mv.visitInsn(MONITORENTER);
            stack(1);
        }
            break;
        case OP_MONITOR_EXIT: {
            mv.visitVarInsn(ALOAD, map(reg));
            mv.visitInsn(MONITOREXIT);
            stack(1);
        }
            break;
        default:
            throw new RuntimeException(
                    String.format("Not support Opcode:[0x%04x]=%s yet!", opcode, DexOpcodeDump.dump(opcode)));
        }
    }

}