接上篇,我们从convertCode开始看
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {主要是3步,上面注释写的比较详细了
IrMethod irMethod = dex2ir(methodNode);//主要是创建了它的stmts 把dex类型的指令转换为ir类型的指令
optimize(irMethod);//对ir类型的指令进行优化
ir2j(irMethod, mv);//把优化后的Ir指令转换为java虚拟机指令
}
先看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就分析完成了。