dex2jar源码解析----解析dex文件

接上篇,我们从convertCode开始看

    public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
        IrMethod irMethod = dex2ir(methodNode);//主要是创建了它的stmts 把dex类型的指令转换为ir类型的指令
        optimize(irMethod);//对ir类型的指令进行优化
        ir2j(irMethod, mv);//把优化后的Ir指令转换为java虚拟机指令
    }
主要是3步,上面注释写的比较详细了

先看dex2ir

    public IrMethod dex2ir(DexMethodNode methodNode) {
        return new Dex2IRConverter()
                .convert(0 != (methodNode.access & DexConstants.ACC_STATIC), methodNode.method, methodNode.codeNode);
    }
新建一个Dex2IRConverter并调用它的convert

public IrMethod convert(boolean isStatic, Method method, DexCodeNode dexCodeNode) {
        this.dexCodeNode = dexCodeNode;//设置DexCodeNode
        IrMethod irMethod = new IrMethod();//创建一个IrMethod
        irMethod.args = method.getParameterTypes();
        irMethod.ret = method.getReturnType();
        irMethod.owner = method.getOwner();
        irMethod.name = method.getName();
        irMethod.isStatic = isStatic;
        target = irMethod;


        insnList = dexCodeNode.stmts;
        for (int i = 0; i < insnList.size(); i++) {//是否有标签
            DexStmtNode stmtNode = insnList.get(i);
            stmtNode.__index = i;//设置 __index
            if (stmtNode instanceof DexLabelStmtNode) {
                DexLabelStmtNode dexLabelStmtNode = (DexLabelStmtNode) stmtNode;
                labelMap.put(dexLabelStmtNode.label, dexLabelStmtNode);
            }
        }

        fixExceptionHandlers();//异常处理指令相关

        BitSet[] exBranch = new BitSet[insnList.size()];
        parentCount = new int[insnList.size()];
        initParentCount(parentCount);//初始化parentCount

        BitSet handlers = new BitSet(insnList.size());
        initExceptionHandlers(dexCodeNode, exBranch, handlers);

        DvmInterpreter interpreter = buildInterpreter();//创建一个DvmInterpreter
        frames = new Dex2IrFrame[insnList.size()];//frames是指令的大小
        emitStmts = new ArrayList[insnList.size()];//
        BitSet access = new BitSet(insnList.size());//已经访问过的指令

        dfs(exBranch, handlers, access, interpreter);


        StmtList stmts = target.stmts;
        stmts.addAll(preEmit);
        for (int i = 0; i < insnList.size(); i++) {
            DexStmtNode p = insnList.get(i);
            if (access.get(i)) {
                List es = emitStmts[i];
                if (es != null) {
                    stmts.addAll(es);//添加到stmts
                }
            } else {
                if (p instanceof DexLabelStmtNode) {
                    stmts.add(getLabel(((DexLabelStmtNode) p).label));
                }
            }
        }
        emitStmts = null;//emitStmts重新设置为null


        Queue queue = new LinkedList<>();

        for (int i1 = 0; i1 < frames.length; i1++) {
            Dex2IrFrame frame = frames[i1];
            if (parentCount[i1] > 1 && frame != null && access.get(i1)) {
                for (int j = 0; j < frame.getTotalRegisters(); j++) {
                    DvmValue v = frame.getReg(j);
                    addToQueue(queue, v);
                }
            }

        }

        while (!queue.isEmpty()) {
            DvmValue v = queue.poll();
            getLocal(v);
            if (v.parent != null) {
                if (v.parent.local == null) {
                    queue.add(v.parent);
                }
            }
            if (v.otherParent != null) {
                for (DvmValue v2 : v.otherParent) {
                    if (v2.local == null) {
                        queue.add(v2);
                    }
                }
            }
        }

        Set phiValues = new HashSet<>();
        List phiLabels = new ArrayList<>();
        for (int i = 0; i < frames.length; i++) {
            Dex2IrFrame frame = frames[i];
            if (parentCount[i] > 1 && frame != null && access.get(i)) {
                DexStmtNode p = insnList.get(i);
                LabelStmt labelStmt = getLabel(((DexLabelStmtNode) p).label);
                List phis = new ArrayList<>();
                for (int j = 0; j < frame.getTotalRegisters(); j++) {
                    DvmValue v = frame.getReg(j);
                    addPhi(v, phiValues, phis);
                }

                labelStmt.phis = phis;
                phiLabels.add(labelStmt);
            }
        }
        if (phiLabels.size() > 0) {
            target.phiLabels = phiLabels;//好像主要是后面指令优化时候要用
        }

        return target;
    }

这个函数比较长,主要做了如下几件事:

1、新建一个IrMethod

2、处理标签

3、处理异常指令

4、初始化parentCount,主要跟跳转等有关

5、调用dfs进行指令转换

6、把处理完的指令添加到target.stmts

我们看下dfs函数

 private void dfs(BitSet[] exBranch, BitSet handlers, BitSet access, DvmInterpreter interpreter) {
        currentEmit = preEmit;

        Dex2IrFrame first = initFirstFrame(dexCodeNode, target);//初始化第一个帧
        if (parentCount[0] > 1) {
            merge(first, 0);
        } else {
            frames[0] = first;
        }
        Stack stack = new Stack<>();
        stack.push(insnList.get(0));
        Dex2IrFrame tmp = new Dex2IrFrame(dexCodeNode.totalRegister);//创建一个临时的帧


        while (!stack.isEmpty()) {
            DexStmtNode p = stack.pop();
            int index = p.__index;//获取指令的索引index
            if (!access.get(index)) {//是否已经处理过
                access.set(index);
            } else {
                continue;
        }
        Dex2IrFrame frame = frames[index];//frames大小为dex指令的大小
        setCurrentEmit(index);//如果为空则新建一个

            if (p instanceof DexLabelStmtNode) {//标签指令节点
                emit(getLabel(((DexLabelStmtNode) p).label));
                if (handlers.get(index)) {
                    Local ex = newLocal();
                    emit(Stmts.nIdentity(ex, Exprs.nExceptionRef("Ljava/lang/Throwable;")));
                    frame.setTmp(new DvmValue(ex));
                }
            }
            BitSet ex = exBranch[index];//跳转
            if (ex != null) {
                for (int i = ex.nextSetBit(0); i >= 0; i = ex.nextSetBit(i + 1)) {
                    merge(frame, i);
                    stack.push(insnList.get(i));
                }
            }

            tmp.init(frame);//用frame初始化tmp
            try {
                if (p.op != null) {
                    switch (p.op) {
                        case RETURN_VOID:
                            emit(nReturnVoid());//添加一个ReturnVoidStmt
                            break;
                        case GOTO:
                        case GOTO_16:
                        case GOTO_32:
                            emit(nGoto(getLabel(((JumpStmtNode) p).label)));
                            break;
                        case NOP:
                            emit(nNop());
                            break;
                        case BAD_OP:
                            emit(nThrow(nInvokeNew(new Value[]{nString("bad dex opcode")}, new String[]{
                                            "Ljava/lang/String;"},
                                    "Ljava/lang/VerifyError;")));
                            break;
                        default:
                            tmp.execute(p, interpreter);//缺省情况执行execute tmp为Dex2IrFrame
                            break;
                    }
                }
            } catch (Exception exception) {
                throw new RuntimeException("Fail on Op " + p.op + " index " + index, exception);
            }


            if (p.op != null) {
                Op op = p.op;
                if (op.canBranch()) {//分支指令,则把条件不满足时的指令偏移入栈
                    JumpStmtNode jump = (JumpStmtNode) p;
                    int targetIndex = indexOf(jump.label);
                    stack.push(insnList.get(targetIndex));
                    merge(tmp, targetIndex);
                }
                if (op.canSwitch()) {
                    BaseSwitchStmtNode switchStmtNode = (BaseSwitchStmtNode) p;
                    for (DexLabel label : switchStmtNode.labels) {
                        int targetIndex = indexOf(label);
                        stack.push(insnList.get(targetIndex));
                        merge(tmp, targetIndex);
                    }
                }
                if (op.canContinue()) {//继续下一条
                    stack.push(insnList.get(index + 1));//下一条指令入栈
                    merge(tmp, index + 1);//把temp和index+1进行merge
                }
            } else {

                stack.push(insnList.get(index + 1));
                merge(tmp, index + 1);

            }
            // cleanup frame it is useless
            if (parentCount[index] <= 1) {//重新设置为null
                frames[index] = null;
            }

        }

    }

这个函数也是比较长,主要做了如下工作:

1、调用initFirstFrame初始化第一个帧

2、依次处理各条指令

我们先看initFirstFrame

 private Dex2IrFrame initFirstFrame(DexCodeNode methodNode, IrMethod target) {
        Dex2IrFrame first = new Dex2IrFrame(methodNode.totalRegister);//总的寄存器个数
        int x = methodNode.totalRegister - methodArgCount(target.args);//减去参数使用的寄存器个数
        if (!target.isStatic) {// not static 非静态方法第一个参数是this
            Local thiz = newLocal();
            emit(Stmts.nIdentity(thiz, Exprs.nThisRef(target.owner)));//新建一个this变量
            first.setReg(x - 1, new DvmValue(thiz));//参数的前面一个寄存器摄者为this
        }
        for (int i = 0; i < target.args.length; i++) {//依次对应参数到寄存器,寄存器的下标依据添加的顺序
            Local p = newLocal();
            emit(Stmts.nIdentity(p, Exprs.nParameterRef(target.args[i], i)));
            first.setReg(x, new DvmValue(p));
            x += sizeofType(target.args[i]);//递增它的类型大小
        }

        if (initAllToZero) {//把所有寄存器的初始值设置为0
            for (int i = 0; i < first.getTotalRegisters(); i++) {
                if (first.getReg(i) == null) {
                    Local p = newLocal();//新建一个Local变量
                    emit(nAssign(p, nInt(0)));//以p和一个整型0参数新建一个AssignStmt并添加到currentEmit
                    first.setReg(i, new DvmValue(p));//以p为参数新建一个DvmValue,并以它为参数调用setReg 把局部变量包装成DvmValue设置到寄存器
                }
            }
        }

        return first;
    }
这里新建一个Dex2IrFrame,参数是寄存器的个数
 static class Dex2IrFrame extends DvmFrame {
        public Dex2IrFrame(int totalRegister) {
            super(totalRegister);
        }
    }
  public DvmFrame(int totalRegister) {
        values = (V[]) new Object[totalRegister];
    }
然后如果是非静态方法,则新建一个this指针,然后调用setReg设置到指定索引寄存器

 public void setReg(int i, V v) {
        if (i > values.length || i < 0) {
            return;
        }
        values[i] = v;
    }
然后

  for (int i = 0; i < target.args.length; i++) {//依次对应参数到寄存器,寄存器的下标依据添加的顺序
            Local p = newLocal();
            emit(Stmts.nIdentity(p, Exprs.nParameterRef(target.args[i], i)));
            first.setReg(x, new DvmValue(p));
            x += sizeofType(target.args[i]);//递增它的类型大小
        }
为每个参数新建一个Local,并设置到Reg,

if (initAllToZero) {//把所有寄存器的初始值设置为0
            for (int i = 0; i < first.getTotalRegisters(); i++) {
                if (first.getReg(i) == null) {
                    Local p = newLocal();//新建一个Local变量
                    emit(nAssign(p, nInt(0)));//以p和一个整型0参数新建一个AssignStmt并添加到currentEmit
                    first.setReg(i, new DvmValue(p));//以p为参数新建一个DvmValue,并以它为参数调用setReg 把局部变量包装成DvmValue设置到寄存器
                }
            }
        }

是否需要把变量初始化为0

回到dfs,接下来处理各个指令

 if (p.op != null) {
                    switch (p.op) {
                        case RETURN_VOID:
                            emit(nReturnVoid());//添加一个ReturnVoidStmt
                            break;
                        case GOTO:
                        case GOTO_16:
                        case GOTO_32:
                            emit(nGoto(getLabel(((JumpStmtNode) p).label)));
                            break;
                        case NOP:
                            emit(nNop());
                            break;
                        case BAD_OP:
                            emit(nThrow(nInvokeNew(new Value[]{nString("bad dex opcode")}, new String[]{
                                            "Ljava/lang/String;"},
                                    "Ljava/lang/VerifyError;")));
                            break;
                        default:
                            tmp.execute(p, interpreter);//缺省情况执行execute tmp为Dex2IrFrame
                            break;
                    }
除了几个特别的指令,其他的都调用execute进行处理

public void execute(DexStmtNode insn, DvmInterpreter interpreter) {
        if (insn.op == null) {// label or others
            return;
        }
        switch (insn.op) {//根据指令的类型调用相应的解析函数
            case CONST://数据定义指令 把数值付给寄存器
            case CONST_4:
            case CONST_16:
            case CONST_HIGH16:
            case CONST_WIDE:
            case CONST_WIDE_16:
            case CONST_WIDE_32:
            case CONST_WIDE_HIGH16:
            case CONST_STRING:
            case CONST_STRING_JUMBO:
            case CONST_CLASS:
                setReg(((ConstStmtNode) insn).a, interpreter.newOperation(insn));//新建一个变量并设置到寄存器,以便后面的指令使用
                setTmp(null);//把temp设置为null
                break;
            case SGET:
            case SGET_BOOLEAN:
            case SGET_BYTE:
            case SGET_CHAR:
            case SGET_OBJECT:
            case SGET_SHORT:
            case SGET_WIDE:
                setReg(((FieldStmtNode) insn).a, interpreter.newOperation(insn));
                setTmp(null);
                break;
            case NEW_INSTANCE:
                setReg(((TypeStmtNode) insn).a, interpreter.newOperation(insn));
                setTmp(null);
                break;
            case MOVE:
            case MOVE_16:
            case MOVE_FROM16:
            case MOVE_OBJECT:
            case MOVE_OBJECT_16:
            case MOVE_OBJECT_FROM16:
            case MOVE_WIDE:
            case MOVE_WIDE_FROM16:
            case MOVE_WIDE_16:
                Stmt2RNode stmt2RNode = (Stmt2RNode) insn;
                setReg(stmt2RNode.a, interpreter.copyOperation(insn, getReg(stmt2RNode.b)));
                setTmp(null);
                break;
            case MOVE_RESULT:
            case MOVE_RESULT_WIDE:
            case MOVE_RESULT_OBJECT:
            case MOVE_EXCEPTION:
                setReg(((Stmt1RNode) insn).a, interpreter.copyOperation(insn, getTmp()));
                setTmp(null);
                break;
            case NOT_INT:
            case NOT_LONG:
            case NEG_DOUBLE:
            case NEG_FLOAT:
            case NEG_INT:
            case NEG_LONG:
            case INT_TO_BYTE:
            case INT_TO_CHAR:
            case INT_TO_DOUBLE:
            case INT_TO_FLOAT:
            case INT_TO_LONG:
            case INT_TO_SHORT:
            case FLOAT_TO_DOUBLE:
            case FLOAT_TO_INT:
            case FLOAT_TO_LONG:
            case DOUBLE_TO_FLOAT:
            case DOUBLE_TO_INT:
            case DOUBLE_TO_LONG:
            case LONG_TO_DOUBLE:
            case LONG_TO_FLOAT:
            case LONG_TO_INT:
            case ARRAY_LENGTH:
                Stmt2RNode stmt2RNode1 = (Stmt2RNode) insn;
                setReg(stmt2RNode1.a, interpreter.unaryOperation(insn, getReg(stmt2RNode1.b)));
                setTmp(null);
                break;
            case IF_EQZ:
            case IF_GEZ:
            case IF_GTZ:
            case IF_LEZ:
            case IF_LTZ:
            case IF_NEZ:
                interpreter.unaryOperation(insn, getReg(((JumpStmtNode) insn).a));
                setTmp(null);
                break;
            case SPARSE_SWITCH:
                interpreter.unaryOperation(insn, getReg(((SparseSwitchStmtNode) insn).a));
                setTmp(null);
                break;
            case PACKED_SWITCH:
                interpreter.unaryOperation(insn, getReg(((PackedSwitchStmtNode) insn).a));
                setTmp(null);
                break;
            case SPUT://字段操作指令,用来对对象的字段进行对鞋操作 s开头的是静态字段i开头的是普通字段
            case SPUT_BOOLEAN:
            case SPUT_BYTE:
            case SPUT_CHAR:
            case SPUT_OBJECT:
            case SPUT_SHORT:
            case SPUT_WIDE:
                interpreter.unaryOperation(insn, getReg(((FieldStmtNode) insn).a));//获取寄存器的值进行操作
                setTmp(null);
                break;
            case IGET:
            case IGET_BOOLEAN:
            case IGET_BYTE:
            case IGET_CHAR:
            case IGET_OBJECT:
            case IGET_SHORT:
            case IGET_WIDE:
                FieldStmtNode fieldStmtNode = (FieldStmtNode) insn;
                setReg(fieldStmtNode.a, interpreter.unaryOperation(insn, getReg(fieldStmtNode.b)));
                setTmp(null);
                break;
            case NEW_ARRAY:
            case INSTANCE_OF: {
                TypeStmtNode typeStmtNode = (TypeStmtNode) insn;
                setReg(typeStmtNode.a, interpreter.unaryOperation(insn, getReg(typeStmtNode.b)));
                setTmp(null);
            }
            break;
            case CHECK_CAST: {
                TypeStmtNode typeStmtNode = (TypeStmtNode) insn;
                setReg(typeStmtNode.a, interpreter.unaryOperation(insn, getReg(typeStmtNode.a)));
                setTmp(null);
            }
            break;
            case MONITOR_ENTER:
            case MONITOR_EXIT:
            case THROW:
                interpreter.unaryOperation(insn, getReg(((Stmt1RNode) insn).a));
                setTmp(null);
                break;
            case RETURN:
            case RETURN_WIDE:
            case RETURN_OBJECT:
                interpreter.returnOperation(insn, getReg(((Stmt1RNode) insn).a));
                setTmp(null);
                break;
            case AGET:
            case AGET_BOOLEAN:
            case AGET_BYTE:
            case AGET_CHAR:
            case AGET_OBJECT:
            case AGET_SHORT:
            case AGET_WIDE:
            case CMP_LONG:
            case CMPG_DOUBLE:
            case CMPG_FLOAT:
            case CMPL_DOUBLE:
            case CMPL_FLOAT:
            case ADD_DOUBLE:
            case ADD_FLOAT:
            case ADD_INT:
            case ADD_LONG:
            case SUB_DOUBLE:
            case SUB_FLOAT:
            case SUB_INT:
            case SUB_LONG:
            case MUL_DOUBLE:
            case MUL_FLOAT:
            case MUL_INT:
            case MUL_LONG:
            case DIV_DOUBLE:
            case DIV_FLOAT:
            case DIV_INT:
            case DIV_LONG:
            case REM_DOUBLE:
            case REM_FLOAT:
            case REM_INT:
            case REM_LONG:
            case AND_INT:
            case AND_LONG:
            case OR_INT:
            case OR_LONG:
            case XOR_INT:
            case XOR_LONG:
            case SHL_INT:
            case SHL_LONG:
            case SHR_INT:
            case SHR_LONG:
            case USHR_INT:
            case USHR_LONG:
                Stmt3RNode stmt3RNode = (Stmt3RNode) insn;
                setReg(stmt3RNode.a, interpreter.binaryOperation(insn, getReg(stmt3RNode.b), getReg(stmt3RNode.c)));
                setTmp(null);
                break;
            case IF_EQ:
            case IF_GE:
            case IF_GT:
            case IF_LE:
            case IF_LT:
            case IF_NE:
                JumpStmtNode jumpStmtNode = (JumpStmtNode) insn;
                interpreter.binaryOperation(insn, getReg(jumpStmtNode.a), getReg(jumpStmtNode.b));
                setTmp(null);
                break;
            case IPUT:
            case IPUT_BOOLEAN:
            case IPUT_BYTE:
            case IPUT_CHAR:
            case IPUT_OBJECT:
            case IPUT_SHORT:
            case IPUT_WIDE:
                FieldStmtNode fieldStmtNode1 = (FieldStmtNode) insn;
                interpreter.binaryOperation(insn, getReg(fieldStmtNode1.b), getReg(fieldStmtNode1.a));
                setTmp(null);
                break;
            case APUT:
            case APUT_BOOLEAN:
            case APUT_BYTE:
            case APUT_CHAR:
            case APUT_OBJECT:
            case APUT_SHORT:
            case APUT_WIDE:
                Stmt3RNode stmt3RNode1 = (Stmt3RNode) insn;
                interpreter.ternaryOperation(insn, getReg(stmt3RNode1.b), getReg(stmt3RNode1.c), getReg(stmt3RNode1.a));
                setTmp(null);
                break;
            case INVOKE_VIRTUAL_RANGE:
            case INVOKE_VIRTUAL:
            case INVOKE_SUPER_RANGE:
            case INVOKE_DIRECT_RANGE:
            case INVOKE_SUPER:
            case INVOKE_DIRECT:
            case INVOKE_STATIC_RANGE:
            case INVOKE_STATIC:
            case INVOKE_INTERFACE_RANGE:
            case INVOKE_INTERFACE: {
                int i = 0;
                MethodStmtNode methodStmtNode = (MethodStmtNode) insn;
                List v;
                if (insn.op == Op.INVOKE_STATIC || insn.op == Op.INVOKE_STATIC_RANGE) {//静态方法
                    v = new ArrayList<>(methodStmtNode.method.getParameterTypes().length);
                } else {//非静态方法添加this
                    v = new ArrayList<>(methodStmtNode.method.getParameterTypes().length + 1);
                    v.add(getReg(methodStmtNode.args[i++]));
                }

                for (String type : methodStmtNode.method.getParameterTypes()) {//添加参数
                    v.add(getReg(methodStmtNode.args[i]));
                    char t = type.charAt(0);
                    if (t == 'J' || t == 'D') {
                        i += 2;
                    } else {
                        i += 1;
                    }
                }
                setTmp(interpreter.naryOperation(insn, v));
            }
            break;
            case FILLED_NEW_ARRAY:
            case FILLED_NEW_ARRAY_RANGE: {
                FilledNewArrayStmtNode filledNewArrayStmtNode = (FilledNewArrayStmtNode) insn;
                List v = new ArrayList<>(filledNewArrayStmtNode.args.length);
                for (int i = 0; i < filledNewArrayStmtNode.args.length; i++) {
                    v.add(getReg(filledNewArrayStmtNode.args[i]));
                }
                setTmp(interpreter.naryOperation(insn, v));
            }
            break;


            case ADD_DOUBLE_2ADDR:
            case ADD_FLOAT_2ADDR:
            case ADD_INT_2ADDR:
            case ADD_LONG_2ADDR:
            case SUB_DOUBLE_2ADDR:
            case SUB_FLOAT_2ADDR:
            case SUB_INT_2ADDR:
            case SUB_LONG_2ADDR:
            case MUL_DOUBLE_2ADDR:
            case MUL_FLOAT_2ADDR:
            case MUL_INT_2ADDR:
            case MUL_LONG_2ADDR:
            case DIV_DOUBLE_2ADDR:
            case DIV_FLOAT_2ADDR:
            case DIV_INT_2ADDR:
            case DIV_LONG_2ADDR:
            case REM_DOUBLE_2ADDR:
            case REM_FLOAT_2ADDR:
            case REM_INT_2ADDR:
            case REM_LONG_2ADDR:
            case AND_INT_2ADDR:
            case AND_LONG_2ADDR:
            case OR_INT_2ADDR:
            case OR_LONG_2ADDR:
            case XOR_INT_2ADDR:
            case XOR_LONG_2ADDR:
            case SHL_INT_2ADDR:
            case SHL_LONG_2ADDR:
            case SHR_INT_2ADDR:
            case SHR_LONG_2ADDR:
            case USHR_INT_2ADDR:
            case USHR_LONG_2ADDR:
                Stmt2RNode stmt2RNode2 = (Stmt2RNode) insn;
                setReg(stmt2RNode2.a, interpreter.binaryOperation(insn, getReg(stmt2RNode2.a), getReg(stmt2RNode2.b)));
                setTmp(null);
                break;
            case ADD_INT_LIT16:
            case ADD_INT_LIT8:
            case RSUB_INT_LIT8:
            case RSUB_INT:
            case MUL_INT_LIT8:
            case MUL_INT_LIT16:
            case DIV_INT_LIT16:
            case DIV_INT_LIT8:
            case REM_INT_LIT16:
            case REM_INT_LIT8:
            case AND_INT_LIT16:
            case AND_INT_LIT8:
            case OR_INT_LIT16:
            case OR_INT_LIT8:
            case XOR_INT_LIT16:
            case XOR_INT_LIT8:
            case SHL_INT_LIT8:
            case SHR_INT_LIT8:
            case USHR_INT_LIT8:
                Stmt2R1NNode stmt2R1NNode = (Stmt2R1NNode) insn;
                setReg(stmt2R1NNode.distReg, interpreter.unaryOperation(insn, getReg(stmt2R1NNode.srcReg)));
                setTmp(null);
                break;
            case FILL_ARRAY_DATA:
                interpreter.unaryOperation(insn,getReg(((FillArrayDataStmtNode)insn).ra));
                setTmp(null);
                break;
            case GOTO:
            case GOTO_16:
            case GOTO_32:
            case RETURN_VOID:
            case BAD_OP:
                setTmp(null);
                break;
            default:
                throw new RuntimeException();
        }
    }
这里对各种指令进行处理,转换为iR指令

这样dex2ir的主要工作就完成了,

接下来是optimize

 public void optimize(IrMethod irMethod) {
                T_cleanLabel.transform(irMethod);
                if (0 != (v3Config & V3.TOPOLOGICAL_SORT)) {
                    // T_topologicalSort.transform(irMethod);
                }
                T_deadCode.transform(irMethod);
                T_removeLocal.transform(irMethod);
                T_removeConst.transform(irMethod);
                T_zero.transform(irMethod);
                if (T_npe.transformReportChanged(irMethod)) {
                    T_deadCode.transform(irMethod);
                    T_removeLocal.transform(irMethod);
                    T_removeConst.transform(irMethod);
                }
                T_new.transform(irMethod);
                T_fillArray.transform(irMethod);
                T_agg.transform(irMethod);
                T_multiArray.transform(irMethod);
                T_voidInvoke.transform(irMethod);
                if (0 != (v3Config & V3.PRINT_IR)) {
                    int i = 0;
                    for (Stmt p : irMethod.stmts) {
                        if (p.st == Stmt.ST.LABEL) {
                            LabelStmt labelStmt = (LabelStmt) p;
                            labelStmt.displayName = "L" + i++;
                        }
                    }
                    System.out.println(irMethod);
                }
                T_type.transform(irMethod);
                T_unssa.transform(irMethod);
                T_ir2jRegAssign.transform(irMethod);
                T_trimEx.transform(irMethod);
            }
这里主要是对前面生成的指令进行一些优化,去掉一些没用的指令

接下来是ir2j把IR指令转换为jvm指令

 @Override
            public void ir2j(IrMethod irMethod, MethodVisitor mv) {
                new IR2JConverter(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config)).convert(irMethod, mv);
            }
    public void convert(IrMethod ir, MethodVisitor asm) {
        mapLabelStmt(ir);//
        reBuildInstructions(ir, asm);//把ir类型(中间类型)的指令转换为java中对应的指令
        reBuildTryCatchBlocks(ir, asm);
    }
mapLabelStmt对指令中的标签进行出来

然后调用reBuildInstructions重构指令

 private void reBuildInstructions(IrMethod ir, MethodVisitor asm) {
        asm = new LdcOptimizeAdapter(asm);//ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能
        int maxLocalIndex = 0;
        for (Local local : ir.locals) {
            maxLocalIndex = Math.max(maxLocalIndex, local._ls_index);
        }
        Map lockMap = new HashMap();
        for (Stmt st : ir.stmts) {
            switch (st.st) {
            case LABEL://标签
                LabelStmt labelStmt = (LabelStmt) st;
                Label label = (Label) labelStmt.tag;
                asm.visitLabel(label);
                if (labelStmt.lineNumber >= 0) {
                    asm.visitLineNumber(labelStmt.lineNumber, label);
                }
                break;
            case ASSIGN: {//赋值
                E2Stmt e2 = (E2Stmt) st;
                Value v1 = e2.op1;//操作数1
                Value v2 = e2.op2;  //操作数2
                switch (v1.vt) {//左边操作数1的类型
                case LOCAL:

                    Local local = ((Local) v1);
                    int i = local._ls_index;

                    boolean skipOrg = false;
                    if (v2.vt == VT.LOCAL && (i == ((Local) v2)._ls_index)) {// check for a=a
                        skipOrg = true;
                    } else if (v1.valueType.charAt(0) == 'I') {// check for IINC
                        if (v2.vt == VT.ADD) {
                            if (isLocalWithIndex(v2.getOp1(), i) && v2.getOp2().vt == VT.CONSTANT) { // a=a+1;
                                int increment = (Integer) ((Constant) v2.getOp2()).value;
                                if (increment >= Short.MIN_VALUE && increment <= Short.MAX_VALUE) {
                                    asm.visitIincInsn(i, increment);
                                    skipOrg = true;
                                }
                            } else if (isLocalWithIndex(v2.getOp2(), i) && v2.getOp1().vt == VT.CONSTANT) { // a=1+a;
                                int increment = (Integer) ((Constant) v2.getOp1()).value;
                                if (increment >= Short.MIN_VALUE && increment <= Short.MAX_VALUE) {
                                    asm.visitIincInsn(i, increment);
                                    skipOrg = true;
                                }
                            }
                        } else if (v2.vt == VT.SUB) {
                            if (isLocalWithIndex(v2.getOp1(), i) && v2.getOp2().vt == VT.CONSTANT) { // a=a-1;
                                int increment = -(Integer) ((Constant) v2.getOp2()).value;
                                if (increment >= Short.MIN_VALUE && increment <= Short.MAX_VALUE) {
                                    asm.visitIincInsn(i, increment);
                                    skipOrg = true;
                                }
                            }
                        }
                    }
                    if (!skipOrg) {
                        accept(v2, asm);
                        if (i >= 0) {
                            asm.visitVarInsn(getOpcode(v1, ISTORE), i);
                        } else if (!v1.valueType.equals("V")) { // skip void type locals
                            switch (v1.valueType.charAt(0)) {
                            case 'J':
                            case 'D':
                                asm.visitInsn(POP2);
                                break;
                            default:
                                asm.visitInsn(POP);
                                break;
                            }
                        }
                    }
                    break;
                case STATIC_FIELD: {//静态变量
                    StaticFieldExpr fe = (StaticFieldExpr) v1;//静态变量表达式
                    accept(v2, asm);//访问右边的变量(入栈)
                    insertI2x(v2.valueType, fe.type, asm);//是否要做类型转换
                    asm.visitFieldInsn(PUTSTATIC, toInternal(fe.owner), fe.name, fe.type);//PUTSTATIC为指定的类的静态域赋值
                    // toInternal去掉前面的L
                    break;
                }
                case FIELD: {
                    FieldExpr fe = (FieldExpr) v1;
                    accept(fe.op, asm);
                    accept(v2, asm);
                    insertI2x(v2.valueType, fe.type, asm);
                    asm.visitFieldInsn(PUTFIELD, toInternal(fe.owner), fe.name, fe.type);
                    break;
                }
                case ARRAY:
                    ArrayExpr ae = (ArrayExpr) v1;
                    accept(ae.op1, asm);
                    accept(ae.op2, asm);
                    accept(v2, asm);
                    String tp1 = ae.op1.valueType;
                    String tp2 = ae.valueType;
                    if (tp1.charAt(0) == '[') {
                        String arrayElementType = tp1.substring(1);
                        insertI2x(v2.valueType, arrayElementType, asm);
                        asm.visitInsn(getOpcode(arrayElementType, IASTORE));
                    } else {
                        asm.visitInsn(getOpcode(tp2, IASTORE));
                    }
                    break;
                }
            }
                break;
            case IDENTITY: {
                E2Stmt e2 = (E2Stmt) st;
                if (e2.op2.vt == VT.EXCEPTION_REF) {
                    int index = ((Local) e2.op1)._ls_index;
                    if (index >= 0) {
                        asm.visitVarInsn(ASTORE, index);
                    } else {
                        asm.visitInsn(POP);
                    }
                }
            }
                break;

            case FILL_ARRAY_DATA:{
                E2Stmt e2 = (E2Stmt) st;
                if (e2.getOp2().vt == VT.CONSTANT) {
                    Object arrayData = ((Constant) e2.getOp2()).value;
                    int arraySize = Array.getLength(arrayData);
                    String arrayValueType = e2.getOp1().valueType;
                    String elementType;
                    if (arrayValueType.charAt(0) == '[') {
                        elementType = arrayValueType.substring(1);
                    } else {
                        elementType = "I";
                    }
                    int iastoreOP = getOpcode(elementType, IASTORE);
                    accept(e2.getOp1(), asm);
                    for (int i = 0; i < arraySize; i++) {
                        asm.visitInsn(DUP);
                        asm.visitLdcInsn(i);
                        asm.visitLdcInsn(Array.get(arrayData, i));
                        asm.visitInsn(iastoreOP);
                    }
                    asm.visitInsn(POP);
                } else {
                    FilledArrayExpr filledArrayExpr = (FilledArrayExpr) e2.getOp2();
                    int arraySize = filledArrayExpr.ops.length;
                    String arrayValueType = e2.getOp1().valueType;
                    String elementType;
                    if (arrayValueType.charAt(0) == '[') {
                        elementType = arrayValueType.substring(1);
                    } else {
                        elementType = "I";
                    }
                    int iastoreOP = getOpcode(elementType, IASTORE);
                    accept(e2.getOp1(), asm);
                    for (int i = 0; i < arraySize; i++) {
                        asm.visitInsn(DUP);
                        asm.visitLdcInsn(i);
                        accept(filledArrayExpr.ops[i], asm);
                        asm.visitInsn(iastoreOP);
                    }
                    asm.visitInsn(POP);
                }
            }
            break;
            case GOTO:
                asm.visitJumpInsn(GOTO, (Label) ((GotoStmt) st).target.tag);
                break;
            case IF:
                reBuildJumpInstructions((IfStmt) st, asm);
                break;
            case LOCK: {
                Value v = ((UnopStmt) st).op;
                accept(v, asm);
                if (optimizeSynchronized) {
                    switch (v.vt) {
                    case LOCAL:
                        // FIXME do we have to disable local due to OptSyncTest ?
                        // break;
                    case CONSTANT: {
                        String key;
                        if (v.vt == VT.LOCAL) {
                            key = "L" + ((Local) v)._ls_index;
                        } else {
                            key = "C" + ((Constant) v).value;
                        }
                        Integer integer = lockMap.get(key);
                        int nIndex = integer != null ? integer : ++maxLocalIndex;
                        asm.visitInsn(DUP);
                        asm.visitVarInsn(getOpcode(v, ISTORE), nIndex);
                        lockMap.put(key, nIndex);
                    }
                        break;
                    default:
                        throw new RuntimeException();
                    }
                }
                asm.visitInsn(MONITORENTER);
            }
                break;
            case UNLOCK: {
                Value v = ((UnopStmt) st).op;
                if (optimizeSynchronized) {
                    switch (v.vt) {
                    case LOCAL:
                    case CONSTANT: {
                        String key;
                        if (v.vt == VT.LOCAL) {
                            key = "L" + ((Local) v)._ls_index;
                        } else {
                            key = "C" + ((Constant) v).value;
                        }
                        Integer integer = lockMap.get(key);
                        if (integer != null) {
                            asm.visitVarInsn(getOpcode(v, ILOAD), integer);
                        } else {
                            accept(v, asm);
                        }
                    }
                        break;
                    // TODO other
                    default: {
                        accept(v, asm);
                        break;
                    }
                    }
                } else {
                    accept(v, asm);
                }
                asm.visitInsn(MONITOREXIT);
            }
                break;
            case NOP:
                break;
            case RETURN: {
                Value v = ((UnopStmt) st).op;
                accept(v, asm);
                insertI2x(v.valueType, ir.ret, asm);
                asm.visitInsn(getOpcode(v, IRETURN));
            }
                break;
            case RETURN_VOID:
                asm.visitInsn(RETURN);//返回指令
                break;
            case LOOKUP_SWITCH: {
                LookupSwitchStmt lss = (LookupSwitchStmt) st;
                accept(lss.op, asm);
                Label targets[] = new Label[lss.targets.length];
                for (int i = 0; i < targets.length; i++) {
                    targets[i] = (Label) lss.targets[i].tag;
                }
                asm.visitLookupSwitchInsn((Label) lss.defaultTarget.tag, lss.lookupValues, targets);
            }
                break;
            case TABLE_SWITCH: {
                TableSwitchStmt tss = (TableSwitchStmt) st;
                accept(tss.op, asm);
                Label targets[] = new Label[tss.targets.length];
                for (int i = 0; i < targets.length; i++) {
                    targets[i] = (Label) tss.targets[i].tag;
                }
                asm.visitTableSwitchInsn(tss.lowIndex, tss.lowIndex + targets.length - 1,
                        (Label) tss.defaultTarget.tag, targets);
            }
                break;
            case THROW:
                accept(((UnopStmt) st).op, asm);
                asm.visitInsn(ATHROW);
                break;
            case VOID_INVOKE:
                Value op = st.getOp();
                accept(op, asm);

                String ret = op.valueType;
                if (op.vt == VT.INVOKE_NEW) {
                    asm.visitInsn(POP);
                } else if (!"V".equals(ret)) {
                    switch (ret.charAt(0)) {
                        case 'J':
                        case 'D':
                            asm.visitInsn(POP2);
                            break;
                        default:
                            asm.visitInsn(POP);
                            break;
                    }
                }
                break;
            default:
                throw new RuntimeException("not support st: " + st.st);
            }

        }
    }

函数开始新建了一个LdcOptimizeAdapter,用来解析Ldc的指令


 private static void accept(Value value, MethodVisitor asm) {

        switch (value.et) {//参数个数
        case E0:
            switch (value.vt) {//值类型
            case LOCAL:
                asm.visitVarInsn(getOpcode(value, ILOAD), ((Local) value)._ls_index);
                break;
            case CONSTANT://常量
                Constant cst = (Constant) value;
                if (cst.value.equals(Constant.Null)) {//是否为空
                    asm.visitInsn(ACONST_NULL);
                } else if (cst.value instanceof Constant.Type) {//Type类型
                    asm.visitLdcInsn(Type.getType(((Constant.Type) cst.value).desc));
                } else {
                    asm.visitLdcInsn(cst.value);
                }
                break;
            case NEW:
                asm.visitTypeInsn(NEW, toInternal(((NewExpr) value).type));
                break;
            case STATIC_FIELD:
                StaticFieldExpr sfe= (StaticFieldExpr) value;
                asm.visitFieldInsn(GETSTATIC,toInternal(sfe.owner),sfe.name,sfe.type);
                break;
            }
            break;
        case E1:
            reBuildE1Expression((E1Expr) value, asm);
            break;
        case E2:
            reBuildE2Expression((E2Expr) value, asm);
            break;
        case En:
            reBuildEnExpression((EnExpr) value, asm);
            break;
        }
    }
主要是转换为jvm指令,出栈,入栈等

当所有的都完成后调用ClassVisitorFactory的visitEnd

public void visitEnd() {
                        super.visitEnd();
                        ClassWriter cw = (ClassWriter) super.cv;

                        byte[] data;
                        try {
                            // FIXME handle 'java.lang.RuntimeException: Method code too large!'
                            data = cw.toByteArray();
                        } catch (Exception ex) {
                            System.err.println(String.format("ASM fail to generate .class file: %s", name));
                            exceptionHandler.handleFileException(ex);
                            return;
                        }
                        try {
                            Path dist1 = dist.resolve(name + ".class");
                            Path parent = dist1.getParent();
                            if (parent != null && !Files.exists(parent)) {
                                Files.createDirectories(parent);
                            }
                            Files.write(dist1, data);
                        } catch (IOException e) {
                            e.printStackTrace(System.err);
                        }
                    }
这里主要是

data = cw.toByteArray();
 public byte[] toByteArray() {
        if (index > 0xFFFF) {
            throw new RuntimeException("Class file too large!");
        }
        // computes the real size of the bytecode of this class
        int size = 24 + 2 * interfaceCount;
        int nbFields = 0;
        FieldWriter fb = firstField;
        while (fb != null) {
            ++nbFields;
            size += fb.getSize();
            fb = (FieldWriter) fb.fv;
        }
        int nbMethods = 0;
        MethodWriter mb = firstMethod;
        while (mb != null) {
            ++nbMethods;
            size += mb.getSize();
            mb = (MethodWriter) mb.mv;
        }
        int attributeCount = 0;
        if (bootstrapMethods != null) {
            // we put it as first attribute in order to improve a bit
            // ClassReader.copyBootstrapMethods
            ++attributeCount;
            size += 8 + bootstrapMethods.length;
            newUTF8("BootstrapMethods");
        }
        if (ClassReader.SIGNATURES && signature != 0) {
            ++attributeCount;
            size += 8;
            newUTF8("Signature");
        }
        if (sourceFile != 0) {
            ++attributeCount;
            size += 8;
            newUTF8("SourceFile");
        }
        if (sourceDebug != null) {
            ++attributeCount;
            size += sourceDebug.length + 6;
            newUTF8("SourceDebugExtension");
        }
        if (enclosingMethodOwner != 0) {
            ++attributeCount;
            size += 10;
            newUTF8("EnclosingMethod");
        }
        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
            ++attributeCount;
            size += 6;
            newUTF8("Deprecated");
        }
        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
            if ((version & 0xFFFF) < Opcodes.V1_5
                    || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
                ++attributeCount;
                size += 6;
                newUTF8("Synthetic");
            }
        }
        if (innerClasses != null) {
            ++attributeCount;
            size += 8 + innerClasses.length;
            newUTF8("InnerClasses");
        }
        if (ClassReader.ANNOTATIONS && anns != null) {
            ++attributeCount;
            size += 8 + anns.getSize();
            newUTF8("RuntimeVisibleAnnotations");
        }
        if (ClassReader.ANNOTATIONS && ianns != null) {
            ++attributeCount;
            size += 8 + ianns.getSize();
            newUTF8("RuntimeInvisibleAnnotations");
        }
        if (ClassReader.ANNOTATIONS && tanns != null) {
            ++attributeCount;
            size += 8 + tanns.getSize();
            newUTF8("RuntimeVisibleTypeAnnotations");
        }
        if (ClassReader.ANNOTATIONS && itanns != null) {
            ++attributeCount;
            size += 8 + itanns.getSize();
            newUTF8("RuntimeInvisibleTypeAnnotations");
        }
        if (attrs != null) {
            attributeCount += attrs.getCount();
            size += attrs.getSize(this, null, 0, -1, -1);
        }
        size += pool.length;
        // allocates a byte vector of this size, in order to avoid unnecessary
        // arraycopy operations in the ByteVector.enlarge() method
        ByteVector out = new ByteVector(size);
        out.putInt(0xCAFEBABE).putInt(version);
        out.putShort(index).putByteArray(pool.data, 0, pool.length);
        int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE
                | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC);
        out.putShort(access & ~mask).putShort(name).putShort(superName);
        out.putShort(interfaceCount);
        for (int i = 0; i < interfaceCount; ++i) {
            out.putShort(interfaces[i]);
        }
        out.putShort(nbFields);
        fb = firstField;
        while (fb != null) {
            fb.put(out);
            fb = (FieldWriter) fb.fv;
        }
        out.putShort(nbMethods);
        mb = firstMethod;
        while (mb != null) {
            mb.put(out);
            mb = (MethodWriter) mb.mv;
        }
        out.putShort(attributeCount);
        if (bootstrapMethods != null) {
            out.putShort(newUTF8("BootstrapMethods"));
            out.putInt(bootstrapMethods.length + 2).putShort(
                    bootstrapMethodsCount);
            out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length);
        }
        if (ClassReader.SIGNATURES && signature != 0) {
            out.putShort(newUTF8("Signature")).putInt(2).putShort(signature);
        }
        if (sourceFile != 0) {
            out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
        }
        if (sourceDebug != null) {
            int len = sourceDebug.length;
            out.putShort(newUTF8("SourceDebugExtension")).putInt(len);
            out.putByteArray(sourceDebug.data, 0, len);
        }
        if (enclosingMethodOwner != 0) {
            out.putShort(newUTF8("EnclosingMethod")).putInt(4);
            out.putShort(enclosingMethodOwner).putShort(enclosingMethod);
        }
        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
            out.putShort(newUTF8("Deprecated")).putInt(0);
        }
        if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
            if ((version & 0xFFFF) < Opcodes.V1_5
                    || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) {
                out.putShort(newUTF8("Synthetic")).putInt(0);
            }
        }
        if (innerClasses != null) {
            out.putShort(newUTF8("InnerClasses"));
            out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
            out.putByteArray(innerClasses.data, 0, innerClasses.length);
        }
        if (ClassReader.ANNOTATIONS && anns != null) {
            out.putShort(newUTF8("RuntimeVisibleAnnotations"));
            anns.put(out);
        }
        if (ClassReader.ANNOTATIONS && ianns != null) {
            out.putShort(newUTF8("RuntimeInvisibleAnnotations"));
            ianns.put(out);
        }
        if (ClassReader.ANNOTATIONS && tanns != null) {
            out.putShort(newUTF8("RuntimeVisibleTypeAnnotations"));
            tanns.put(out);
        }
        if (ClassReader.ANNOTATIONS && itanns != null) {
            out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations"));
            itanns.put(out);
        }
        if (attrs != null) {
            attrs.put(this, null, 0, -1, -1, out);
        }
        if (invalidFrames) {
            anns = null;
            ianns = null;
            attrs = null;
            innerClassesCount = 0;
            innerClasses = null;
            bootstrapMethodsCount = 0;
            bootstrapMethods = null;
            firstField = null;
            lastField = null;
            firstMethod = null;
            lastMethod = null;
            computeMaxs = false;
            computeFrames = true;
            invalidFrames = false;
            new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES);
            return toByteArray();
        }
        return out.data;
    }


这里就是按照class文件的格式写入到class文件,如常量池,字段,方法等。

到这里,dex转jar就分析完成了。










你可能感兴趣的:(dex2jar源码解析----解析dex文件)