com.googlecode.dex2jar.v3.V3CodeAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.dex2jar.v3.V3CodeAdapter.java

Source

/*
 * Copyright (c) 2009-2012 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 com.googlecode.dex2jar.v3;

import static com.googlecode.dex2jar.ir.Constant.nClass;
import static com.googlecode.dex2jar.ir.Constant.nInt;
import static com.googlecode.dex2jar.ir.Constant.nLong;
import static com.googlecode.dex2jar.ir.Constant.nString;
import static com.googlecode.dex2jar.ir.expr.Exprs.box;
import static com.googlecode.dex2jar.ir.expr.Exprs.nAdd;
import static com.googlecode.dex2jar.ir.expr.Exprs.nAnd;
import static com.googlecode.dex2jar.ir.expr.Exprs.nArray;
import static com.googlecode.dex2jar.ir.expr.Exprs.nCast;
import static com.googlecode.dex2jar.ir.expr.Exprs.nCheckCast;
import static com.googlecode.dex2jar.ir.expr.Exprs.nDCmpg;
import static com.googlecode.dex2jar.ir.expr.Exprs.nDCmpl;
import static com.googlecode.dex2jar.ir.expr.Exprs.nDiv;
import static com.googlecode.dex2jar.ir.expr.Exprs.nEq;
import static com.googlecode.dex2jar.ir.expr.Exprs.nExceptionRef;
import static com.googlecode.dex2jar.ir.expr.Exprs.nFCmpg;
import static com.googlecode.dex2jar.ir.expr.Exprs.nFCmpl;
import static com.googlecode.dex2jar.ir.expr.Exprs.nField;
import static com.googlecode.dex2jar.ir.expr.Exprs.nGe;
import static com.googlecode.dex2jar.ir.expr.Exprs.nGt;
import static com.googlecode.dex2jar.ir.expr.Exprs.nInstanceOf;
import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeInterface;
import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeSpecial;
import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeStatic;
import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeVirtual;
import static com.googlecode.dex2jar.ir.expr.Exprs.nLCmp;
import static com.googlecode.dex2jar.ir.expr.Exprs.nLe;
import static com.googlecode.dex2jar.ir.expr.Exprs.nLength;
import static com.googlecode.dex2jar.ir.expr.Exprs.nLocal;
import static com.googlecode.dex2jar.ir.expr.Exprs.nLt;
import static com.googlecode.dex2jar.ir.expr.Exprs.nMul;
import static com.googlecode.dex2jar.ir.expr.Exprs.nNe;
import static com.googlecode.dex2jar.ir.expr.Exprs.nNeg;
import static com.googlecode.dex2jar.ir.expr.Exprs.nNew;
import static com.googlecode.dex2jar.ir.expr.Exprs.nNewArray;
import static com.googlecode.dex2jar.ir.expr.Exprs.nNot;
import static com.googlecode.dex2jar.ir.expr.Exprs.nOr;
import static com.googlecode.dex2jar.ir.expr.Exprs.nParameterRef;
import static com.googlecode.dex2jar.ir.expr.Exprs.nRem;
import static com.googlecode.dex2jar.ir.expr.Exprs.nShl;
import static com.googlecode.dex2jar.ir.expr.Exprs.nShr;
import static com.googlecode.dex2jar.ir.expr.Exprs.nStaticField;
import static com.googlecode.dex2jar.ir.expr.Exprs.nSub;
import static com.googlecode.dex2jar.ir.expr.Exprs.nThisRef;
import static com.googlecode.dex2jar.ir.expr.Exprs.nUshr;
import static com.googlecode.dex2jar.ir.expr.Exprs.nXor;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nAssign;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nGoto;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nIdentity;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nIf;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nLock;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nLookupSwitch;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nReturn;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nReturnVoid;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nTableSwitch;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nThrow;
import static com.googlecode.dex2jar.ir.stmt.Stmts.nUnLock;

import java.util.Arrays;

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

import com.googlecode.dex2jar.DexException;
import com.googlecode.dex2jar.DexLabel;
import com.googlecode.dex2jar.DexOpcodes;
import com.googlecode.dex2jar.Field;
import com.googlecode.dex2jar.Method;
import com.googlecode.dex2jar.ir.Constant;
import com.googlecode.dex2jar.ir.IrMethod;
import com.googlecode.dex2jar.ir.Local;
import com.googlecode.dex2jar.ir.LocalVar;
import com.googlecode.dex2jar.ir.Trap;
import com.googlecode.dex2jar.ir.Value;
import com.googlecode.dex2jar.ir.stmt.LabelStmt;
import com.googlecode.dex2jar.ir.stmt.StmtList;
import com.googlecode.dex2jar.visitors.DexCodeVisitor;

/**
 * @author <a href="mailto:pxb1988@gmail.com">Panxiaobo</a>
 * @version $Rev$
 */
public class V3CodeAdapter implements DexCodeVisitor, Opcodes, DexOpcodes {

    private static LabelStmt toLabelStmt(DexLabel label) {
        LabelStmt ls = (LabelStmt) label.info;
        if (ls == null) {
            ls = new LabelStmt(new Label());
            label.info = ls;
        }
        return ls;
    }

    protected IrMethod irMethod;
    private StmtList list;
    private Local[] locals;
    /**
     * ?
     */
    private int tmp_reg;

    /**
     * @param mv
     */
    public V3CodeAdapter(int accessFlags, IrMethod irMethod) {
        super();
        this.list = irMethod.stmts;
        this.irMethod = irMethod;
    }

    @Override
    public void visitArguments(int total, int[] args) {
        Local[] locals = new Local[total + 1];
        this.locals = locals;
        this.tmp_reg = total;
        {
            int i = 0;
            if ((irMethod.access & Opcodes.ACC_STATIC) == 0) {
                Local _this = nLocal("this");
                list.add(nIdentity(_this, nThisRef(this.irMethod.owner)));
                locals[args[i]] = _this;
                i++;
            }
            int j = 0;
            for (; i < args.length; i++, j++) {
                Local _arg = nLocal("arg_" + args[i]);
                list.add(nIdentity(_arg, nParameterRef(this.irMethod.args[j], j)));
                locals[args[i]] = _arg;
            }
        }
        for (int i = 0; i < locals.length; i++) {
            if (locals[i] == null) {
                locals[i] = nLocal("a" + i);
            }
        }
    }

    @Override
    public void visitArrayStmt(int opcode, int formOrToReg, int arrayReg, int indexReg, int xt) {
        switch (opcode) {
        case OP_APUT:
            list.add(nAssign(nArray(locals[arrayReg], locals[indexReg]), locals[formOrToReg]));
            break;
        case OP_AGET:
            list.add(nAssign(locals[formOrToReg], nArray(locals[arrayReg], locals[indexReg])));
            break;
        }
    }

    @Override
    public void visitBinopLitXStmt(int opcode, int distReg, int srcReg, int constant) {
        Local dist = locals[distReg];
        Local a = locals[srcReg];
        Constant b = Constant.nInt(constant);
        switch (opcode) {
        case OP_ADD_INT_LIT_X:
            list.add(nAssign(dist, nAdd(a, b, Type.INT_TYPE)));
            break;
        case OP_RSUB_INT_LIT_X:
            list.add(nAssign(dist, nSub(b, a, Type.INT_TYPE)));
            break;
        case OP_MUL_INT_LIT_X:
            list.add(nAssign(dist, nMul(a, b, Type.INT_TYPE)));
            break;
        case OP_DIV_INT_LIT_X:
            list.add(nAssign(dist, nDiv(a, b, Type.INT_TYPE)));
            break;
        case OP_REM_INT_LIT_X:
            list.add(nAssign(dist, nRem(a, b, Type.INT_TYPE)));
            break;
        case OP_AND_INT_LIT_X:
            list.add(nAssign(dist, nAnd(a, b, Type.INT_TYPE)));
            break;
        case OP_OR_INT_LIT_X:
            list.add(nAssign(dist, nOr(a, b, Type.INT_TYPE)));
            break;
        case OP_XOR_INT_LIT_X:
            list.add(nAssign(dist, nXor(a, b, Type.INT_TYPE)));
            break;
        case OP_SHL_INT_LIT_X:
            list.add(nAssign(dist, nShl(a, b, Type.INT_TYPE)));
            break;
        case OP_SHR_INT_LIT_X:
            list.add(nAssign(dist, nShr(a, b, Type.INT_TYPE)));
            break;
        case OP_USHR_INT_LIT_X:
            list.add(nAssign(dist, nUshr(a, b, Type.INT_TYPE)));
            break;

        }
    }

    @Override
    public void visitBinopStmt(int opcode, int toReg, int r1, int r2, int xt) {
        Local dist = locals[toReg];
        Local a = locals[r1];
        Local b = locals[r2];
        Type type = null;
        switch (xt) {
        case TYPE_INT:
            type = Type.INT_TYPE;
            break;
        case TYPE_LONG:
            type = Type.LONG_TYPE;
            break;
        case TYPE_FLOAT:
            type = Type.FLOAT_TYPE;
            break;
        case TYPE_DOUBLE:
            type = Type.DOUBLE_TYPE;
            break;
        default:
            throw new DexException();
        }
        switch (opcode) {
        case OP_ADD:
            list.add(nAssign(dist, nAdd(a, b, type)));
            break;
        case OP_SUB:
            list.add(nAssign(dist, nSub(a, b, type)));
            break;
        case OP_MUL:
            list.add(nAssign(dist, nMul(a, b, type)));
            break;
        case OP_DIV:
            list.add(nAssign(dist, nDiv(a, b, type)));
            break;
        case OP_REM:
            list.add(nAssign(dist, nRem(a, b, type)));
            break;
        case OP_AND:
            list.add(nAssign(dist, nAnd(a, b, type)));
            break;
        case OP_OR:
            list.add(nAssign(dist, nOr(a, b, type)));
            break;
        case OP_XOR:
            list.add(nAssign(dist, nXor(a, b, type)));
            break;
        case OP_SHL:
            list.add(nAssign(dist, nShl(a, b, type)));
            break;
        case OP_SHR:
            list.add(nAssign(dist, nShr(a, b, type)));
            break;
        case OP_USHR:
            list.add(nAssign(dist, nUshr(a, b, type)));
            break;
        }
    }

    @Override
    public void visitClassStmt(int opcode, int a, int b, String type) {
        switch (opcode) {
        case OP_INSTANCE_OF:
            list.add(nAssign(locals[a], nInstanceOf(locals[b], Type.getType(type))));
            break;
        case OP_NEW_ARRAY:
            list.add(nAssign(locals[a], nNewArray(Type.getType(type.substring(1)), locals[b])));
            break;
        }
    }

    @Override
    public void visitClassStmt(int opcode, int saveTo, String type) {
        switch (opcode) {
        case OP_CHECK_CAST:
            list.add(nAssign(locals[saveTo], nCheckCast(locals[saveTo], Type.getType(type))));
            break;
        case OP_NEW_INSTANCE:
            list.add(nAssign(locals[saveTo], nNew(Type.getType(type))));
            break;
        }

    }

    @Override
    public void visitCmpStmt(int opcode, int distReg, int bB, int cC, int xt) {
        Local dist = locals[distReg];
        Local a = locals[bB];
        Local b = locals[cC];
        switch (opcode) {
        case OP_CMPL:
            if (xt == TYPE_FLOAT) {
                list.add(nAssign(dist, nFCmpl(a, b)));
            } else {
                list.add(nAssign(dist, nDCmpl(a, b)));
            }
            break;
        case OP_CMPG:
            if (xt == TYPE_FLOAT) {
                list.add(nAssign(dist, nFCmpg(a, b)));
            } else {
                list.add(nAssign(dist, nDCmpg(a, b)));
            }
            break;
        case OP_CMP:
            list.add(nAssign(dist, nLCmp(a, b)));
            break;
        }
    }

    @Override
    public void visitConstStmt(int opcode, int toReg, Object value, int xt) {
        switch (opcode) {
        case OP_CONST:
            if (xt == TYPE_SINGLE) {
                list.add(nAssign(locals[toReg], nInt((Integer) value)));
            } else {
                list.add(nAssign(locals[toReg], nLong((Long) value)));
            }
            break;
        case OP_CONST_STRING:
            list.add(nAssign(locals[toReg], nString((String) value)));
            break;
        case OP_CONST_CLASS:
            list.add(nAssign(locals[toReg], nClass(Type.getType((String) value))));
            break;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.googlecode.dex2jar.visitors.DexCodeVisitor#visitEnd()
     */
    @Override
    public void visitEnd() {
        irMethod.locals.addAll(Arrays.asList(this.locals));
        this.locals = null;
        // for (Stmt stmt : list) {// clean label.info
        // if (stmt.st == ST.LABEL) {
        // ((LabelStmt) stmt).label.info = null;
        // }
        // }

    }

    @Override
    public void visitFieldStmt(int opcode, int fromOrToReg, Field field, int xt) {
        switch (opcode) {

        case OP_SGET:
            list.add(nAssign(locals[fromOrToReg],
                    nStaticField(Type.getType(field.getOwner()), field.getName(), Type.getType(field.getType()))));
            break;
        case OP_SPUT:
            list.add(nAssign(
                    nStaticField(Type.getType(field.getOwner()), field.getName(), Type.getType(field.getType())),
                    locals[fromOrToReg]));
            break;
        }
    }

    @Override
    public void visitFieldStmt(int opcode, int fromOrToReg, int objReg, Field field, int xt) {
        switch (opcode) {

        case OP_IGET:
            list.add(nAssign(locals[fromOrToReg], nField(locals[objReg], Type.getType(field.getOwner()),
                    field.getName(), Type.getType(field.getType()))));
            break;
        case OP_IPUT:
            list.add(nAssign(nField(locals[objReg], Type.getType(field.getOwner()), field.getName(),
                    Type.getType(field.getType())), locals[fromOrToReg]));
            break;
        }
    }

    @Override
    public void visitFillArrayStmt(int opcode, int aA, int elemWidth, int initLength, Object[] values) {
        Local array = locals[aA];
        Type type = null;
        switch (elemWidth) {
        case 1:
            type = Type.BYTE_TYPE;
            break;
        case 2:
            type = Type.SHORT_TYPE;
            break;
        case 4:
            type = Type.INT_TYPE;
            break;
        case 8:
            type = Type.LONG_TYPE;
            break;
        }

        for (int i = 0; i < initLength; i++) {
            list.add(nAssign(nArray(array, Constant.nInt(i)), Constant.n(type, values[i])));
        }
    }

    @Override
    public void visitFilledNewArrayStmt(int opcode, int[] args, String type) {
        Local array = locals[tmp_reg];
        Type elem = Type.getType(type).getElementType();
        list.add(nAssign(array, nNewArray(elem, Constant.nInt(args.length))));
        for (int i = 0; i < args.length; i++) {
            list.add(nAssign(nArray(array, Constant.nInt(i)), locals[args[i]]));
        }
    }

    @Override
    public void visitJumpStmt(int opcode, int r1, int r2, DexLabel label) {
        Local a = locals[r1];
        Local b = locals[r2];
        LabelStmt ls = toLabelStmt(label);
        switch (opcode) {
        case OP_IF_EQ:
            list.add(nIf(nEq(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_NE:
            list.add(nIf(nNe(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_LT:
            list.add(nIf(nLt(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_GE:
            list.add(nIf(nGe(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_GT:
            list.add(nIf(nGt(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_LE:
            list.add(nIf(nLe(a, b, Type.INT_TYPE), ls));
            break;
        }
    }

    @Override
    public void visitJumpStmt(int opcode, int reg, DexLabel label) {
        Local a = locals[reg];
        Value b = nInt(0);
        LabelStmt ls = toLabelStmt(label);
        switch (opcode) {
        case OP_IF_EQZ:
            list.add(nIf(nEq(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_NEZ:
            list.add(nIf(nNe(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_LTZ:
            list.add(nIf(nLt(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_GEZ:
            list.add(nIf(nGe(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_GTZ:
            list.add(nIf(nGt(a, b, Type.INT_TYPE), ls));
            break;
        case OP_IF_LEZ:
            list.add(nIf(nLe(a, b, Type.INT_TYPE), ls));
            break;
        }
    }

    @Override
    public void visitJumpStmt(int opcode, DexLabel label) {
        list.add(nGoto(toLabelStmt(label)));
    }

    @Override
    public void visitLabel(DexLabel label) {
        list.add(toLabelStmt(label));
    }

    @Override
    public void visitLookupSwitchStmt(int opcode, int aA, DexLabel label, int[] cases, DexLabel[] labels) {
        LabelStmt[] lss = new LabelStmt[cases.length];
        for (int i = 0; i < cases.length; i++) {
            lss[i] = toLabelStmt(labels[i]);
        }
        list.add(nLookupSwitch(locals[aA], cases, lss, toLabelStmt(label)));
    }

    @Override
    public void visitMethodStmt(int opcode, int[] args, Method method) {
        Value[] vs = new Value[args.length];
        for (int j = 0; j < vs.length; j++) {
            vs[j] = locals[args[j]];
        }
        Value saveTo = locals[tmp_reg];
        Value invoke = null;
        switch (opcode) {
        case OP_INVOKE_VIRTUAL:
            invoke = nInvokeVirtual(vs, Type.getType(method.getOwner()), method.getName(),
                    Type.getArgumentTypes(method.getDesc()), Type.getType(method.getReturnType()));
            break;
        case OP_INVOKE_SUPER:
        case OP_INVOKE_DIRECT:
            invoke = nInvokeSpecial(vs, Type.getType(method.getOwner()), method.getName(),
                    Type.getArgumentTypes(method.getDesc()), Type.getType(method.getReturnType()));
            break;
        case OP_INVOKE_STATIC:
            invoke = nInvokeStatic(vs, Type.getType(method.getOwner()), method.getName(),
                    Type.getArgumentTypes(method.getDesc()), Type.getType(method.getReturnType()));
            break;
        case OP_INVOKE_INTERFACE:
            invoke = nInvokeInterface(vs, Type.getType(method.getOwner()), method.getName(),
                    Type.getArgumentTypes(method.getDesc()), Type.getType(method.getReturnType()));
            break;
        }
        list.add(nAssign(saveTo, invoke));
    }

    @Override
    public void visitMonitorStmt(int opcode, int reg) {
        switch (opcode) {
        case OP_MONITOR_ENTER:
            list.add(nLock(locals[reg]));
            break;
        case OP_MONITOR_EXIT:
            list.add(nUnLock(locals[reg]));
            break;
        }
    }

    @Override
    public void visitMoveStmt(int opcode, int toReg, int xt) {
        switch (opcode) {
        case OP_MOVE_RESULT:
            list.add(nAssign(locals[toReg], locals[tmp_reg]));
            break;
        case OP_MOVE_EXCEPTION:
            list.add(nIdentity(locals[toReg], nExceptionRef(Type.getType(Throwable.class))));
            break;
        }
    }

    @Override
    public void visitMoveStmt(int opcode, int toReg, int fromReg, int xt) {
        list.add(nAssign(locals[toReg], locals[fromReg]));
    }

    @Override
    public void visitReturnStmt(int opcode) {
        list.add(nReturnVoid());
    }

    @Override
    public void visitReturnStmt(int opcode, int reg, int xt) {
        switch (opcode) {
        case OP_THROW:
            list.add(nThrow(locals[reg]));
            break;
        case OP_RETURN:
            list.add(nReturn(locals[reg]));
            break;
        }

    }

    @Override
    public void visitTableSwitchStmt(int opcode, int aA, DexLabel label, int first_case, int last_case,
            DexLabel[] labels) {
        LabelStmt[] lss = new LabelStmt[labels.length];
        for (int i = 0; i < labels.length; i++) {
            lss[i] = toLabelStmt(labels[i]);
        }
        list.add(nTableSwitch(locals[aA], first_case, last_case, lss, toLabelStmt(label)));

    }

    @Override
    public void visitTryCatch(DexLabel start, DexLabel end, DexLabel[] handlers, String[] types) {
        LabelStmt xlabelStmts[] = new LabelStmt[types.length];
        Type[] xtypes = new Type[types.length];
        for (int i = 0; i < types.length; i++) {
            xlabelStmts[i] = toLabelStmt(handlers[i]);
            xtypes[i] = types[i] == null ? null : Type.getType(types[i]);
        }
        irMethod.traps.add(new Trap(toLabelStmt(start), toLabelStmt(end), xlabelStmts, xtypes));
    }

    @Override
    public void visitUnopStmt(int opcode, int toReg, int fromReg, int xt) {
        Value dist = locals[toReg];
        Value src = locals[fromReg];
        Type type = null;
        switch (xt) {
        case TYPE_INT:
            type = Type.INT_TYPE;
            break;
        case TYPE_LONG:
            type = Type.LONG_TYPE;
            break;
        case TYPE_FLOAT:
            type = Type.FLOAT_TYPE;
            break;
        case TYPE_DOUBLE:
            type = Type.DOUBLE_TYPE;
            break;
        }
        switch (opcode) {
        case OP_ARRAY_LENGTH:
            list.add(nAssign(dist, nLength(src)));
            break;
        case OP_NEG:
            list.add(nAssign(dist, nNeg(src, type)));
            break;
        case OP_NOT:
            list.add(nAssign(dist, nNot(src, type)));
            break;
        }
    }

    @Override
    public void visitUnopStmt(int opcode, int toReg, int fromReg, int xta, int xtb) {
        Value dist = locals[toReg];
        Value src = locals[fromReg];
        switch (opcode) {
        case OP_X_TO_Y:
            Type from;
            switch (xta) {
            case TYPE_INT:
                from = Type.INT_TYPE;
                break;
            case TYPE_FLOAT:
                from = Type.FLOAT_TYPE;
                break;
            case TYPE_DOUBLE:
                from = Type.DOUBLE_TYPE;
                break;
            case TYPE_LONG:
                from = Type.LONG_TYPE;
                break;
            default:
                throw new RuntimeException();
            }
            Type to;
            switch (xtb) {
            case TYPE_LONG:
                to = Type.LONG_TYPE;
                break;
            case TYPE_FLOAT:
                to = Type.FLOAT_TYPE;
                break;
            case TYPE_DOUBLE:
                to = Type.DOUBLE_TYPE;
                break;
            case TYPE_INT:
                to = Type.INT_TYPE;
                break;
            case TYPE_BYTE:
                to = Type.BYTE_TYPE;
                break;
            case TYPE_CHAR:
                to = Type.CHAR_TYPE;
                break;
            case TYPE_SHORT:
                to = Type.SHORT_TYPE;
                break;
            default:
                throw new RuntimeException();
            }
            list.add(nAssign(dist, nCast(src, from, to)));
            break;

        }
    }

    @Override
    public void visitLineNumber(int line, DexLabel label) {
        toLabelStmt(label).lineNumber = line;
    }

    @Override
    public void visitLocalVariable(String name, String type, String signature, DexLabel start, DexLabel end,
            int reg) {
        irMethod.vars
                .add(new LocalVar(name, type, signature, toLabelStmt(start), toLabelStmt(end), box(locals[reg])));
    }
}