dex2jar源码解析----解析dex文件<三>

时间:2022-04-23 17:17:28

接上篇,我们从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<DvmValue> 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<Stmt> 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<DvmValue> 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<com.googlecode.dex2jar.ir.expr.Value> phiValues = new HashSet<>();        List<LabelStmt> 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<AssignStmt> 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<DvmValue> interpreter) {        currentEmit = preEmit;        Dex2IrFrame first = initFirstFrame(dexCodeNode, target);//初始化第一个帧        if (parentCount[0] > 1) {            merge(first, 0);        } else {            frames[0] = first;        }        Stack<DexStmtNode> 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<DvmValue> {        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<V> 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> 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> 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<String, Integer> lockMap = new HashMap<String, Integer>();        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就分析完成了。