Java tutorial
/* * Copyright (c) 2009-2012 Panxiaobo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.googlecode.d2j.dex; import static com.googlecode.dex2jar.ir.expr.Exprs.nAdd; import static com.googlecode.dex2jar.ir.expr.Exprs.nAnd; import static com.googlecode.dex2jar.ir.expr.Exprs.nArray; import static com.googlecode.dex2jar.ir.expr.Exprs.nArrayValue; import static com.googlecode.dex2jar.ir.expr.Exprs.nCast; import static com.googlecode.dex2jar.ir.expr.Exprs.nCheckCast; import static com.googlecode.dex2jar.ir.expr.Exprs.nDCmpg; import static com.googlecode.dex2jar.ir.expr.Exprs.nDCmpl; import static com.googlecode.dex2jar.ir.expr.Exprs.nDiv; import static com.googlecode.dex2jar.ir.expr.Exprs.nExceptionRef; import static com.googlecode.dex2jar.ir.expr.Exprs.nFCmpg; import static com.googlecode.dex2jar.ir.expr.Exprs.nFCmpl; import static com.googlecode.dex2jar.ir.expr.Exprs.nField; import static com.googlecode.dex2jar.ir.expr.Exprs.nInstanceOf; import static com.googlecode.dex2jar.ir.expr.Exprs.nInt; import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeInterface; import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeNew; import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeSpecial; import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeStatic; import static com.googlecode.dex2jar.ir.expr.Exprs.nInvokeVirtual; import static com.googlecode.dex2jar.ir.expr.Exprs.nLCmp; import static com.googlecode.dex2jar.ir.expr.Exprs.nLength; import static com.googlecode.dex2jar.ir.expr.Exprs.nLong; import static com.googlecode.dex2jar.ir.expr.Exprs.nMul; import static com.googlecode.dex2jar.ir.expr.Exprs.nNeg; import static com.googlecode.dex2jar.ir.expr.Exprs.nNew; import static com.googlecode.dex2jar.ir.expr.Exprs.nNewArray; import static com.googlecode.dex2jar.ir.expr.Exprs.nNot; import static com.googlecode.dex2jar.ir.expr.Exprs.nOr; import static com.googlecode.dex2jar.ir.expr.Exprs.nRem; import static com.googlecode.dex2jar.ir.expr.Exprs.nShl; import static com.googlecode.dex2jar.ir.expr.Exprs.nShr; import static com.googlecode.dex2jar.ir.expr.Exprs.nStaticField; import static com.googlecode.dex2jar.ir.expr.Exprs.nString; import static com.googlecode.dex2jar.ir.expr.Exprs.nSub; import static com.googlecode.dex2jar.ir.expr.Exprs.nType; import static com.googlecode.dex2jar.ir.expr.Exprs.nUshr; import static com.googlecode.dex2jar.ir.expr.Exprs.nXor; import static com.googlecode.dex2jar.ir.stmt.Stmts.*; import java.util.*; import com.googlecode.d2j.node.DexCodeNode; import com.googlecode.d2j.visitors.DexDebugVisitor; import com.googlecode.dex2jar.ir.TypeClass; import org.objectweb.asm.Opcodes; import com.googlecode.d2j.DexLabel; import com.googlecode.d2j.DexConstants; import com.googlecode.d2j.DexType; import com.googlecode.d2j.Field; import com.googlecode.d2j.Method; import com.googlecode.d2j.reader.Op; import com.googlecode.d2j.visitors.DexCodeVisitor; import com.googlecode.dex2jar.ir.IrMethod; import com.googlecode.dex2jar.ir.Trap; import com.googlecode.dex2jar.ir.expr.Exprs; import com.googlecode.dex2jar.ir.expr.Local; import com.googlecode.dex2jar.ir.expr.Value; import com.googlecode.dex2jar.ir.stmt.LabelStmt; import com.googlecode.dex2jar.ir.stmt.Stmt; import com.googlecode.dex2jar.ir.stmt.StmtList; import com.googlecode.dex2jar.ir.stmt.Stmts; /** * @author <a href="mailto:pxb1988@gmail.com">Panxiaobo</a> * @version $Rev$ */ public class Dex2IrAdapter extends DexCodeVisitor implements Opcodes, DexConstants { protected IrMethod irMethod; private Method method; private boolean isStatic; private StmtList list; private Local[] locals; Map<DexLabel, LabelStmt> labelStmtMap = new HashMap<>(); /** * ? */ private Local tmpLocal; /** * @param isStatic * @param method */ public Dex2IrAdapter(boolean isStatic, Method method) { super(); IrMethod irMethod = new IrMethod(); irMethod.args = method.getParameterTypes(); irMethod.ret = method.getReturnType(); irMethod.owner = method.getOwner(); irMethod.name = method.getName(); irMethod.isStatic = isStatic; this.irMethod = irMethod; this.list = irMethod.stmts; this.irMethod = irMethod; this.method = method; this.isStatic = isStatic; } private LabelStmt toLabelStmt(DexLabel label) { LabelStmt ls = labelStmtMap.get(label); if (ls == null) { ls = new LabelStmt(); labelStmtMap.put(label, ls); } return ls; } static int countParameterRegisters(Method m, boolean isStatic) { int a = isStatic ? 0 : 1; for (String t : m.getParameterTypes()) { switch (t.charAt(0)) { case 'J': case 'D': a += 2; break; default: a += 1; break; } } return a; } void x(Stmt stmt) { list.add(stmt); } @Override public void visitRegister(int total) { Local[] locals = new Local[total]; this.locals = locals; this.tmpLocal = new Local(total); for (int i = 0; i < locals.length; i++) { locals[i] = new Local(i); } int nextReg = total - countParameterRegisters(method, isStatic); int nextReg0 = nextReg; if (!isStatic) {// is not static x(Stmts.nIdentity(locals[nextReg], Exprs.nThisRef(method.getOwner()))); nextReg++; } String[] args = method.getParameterTypes(); for (int i = 0; i < args.length; i++) { String t = args[i]; x(Stmts.nIdentity(locals[nextReg], Exprs.nParameterRef(t, i))); nextReg++; if (t.equals("J") || t.equals("D")) { nextReg++; } } // simple fix for issue 219, init all tmp register to 0 at the start of insn. for (int i = 0; i < nextReg0; i++) { x(Stmts.nAssign(locals[i], nInt(0))); } x(Stmts.nAssign(tmpLocal, nInt(0))); } @Override public void visitStmt2R1N(Op op, int a, int b, int content) { Local va = locals[a]; Local vb = locals[b]; Value to; switch (op) { case ADD_INT_LIT16: case ADD_INT_LIT8: to = nAdd(vb, nInt(content), "I"); break; case RSUB_INT_LIT8: case RSUB_INT:// to = nSub(nInt(content), vb, "I"); break; case MUL_INT_LIT8: case MUL_INT_LIT16: to = nMul(vb, nInt(content), "I"); break; case DIV_INT_LIT16: case DIV_INT_LIT8: to = nDiv(vb, nInt(content), "I"); break; case REM_INT_LIT16: case REM_INT_LIT8: to = nRem(vb, nInt(content), "I"); break; case AND_INT_LIT16: case AND_INT_LIT8: to = nAnd(vb, nInt(content), content < 0 || content > 1 ? "I" : TypeClass.ZI.name); break; case OR_INT_LIT16: case OR_INT_LIT8: to = nOr(vb, nInt(content), content < 0 || content > 1 ? "I" : TypeClass.ZI.name); break; case XOR_INT_LIT16: case XOR_INT_LIT8: to = nXor(vb, nInt(content), content < 0 || content > 1 ? "I" : TypeClass.ZI.name); break; case SHL_INT_LIT8: to = nShl(vb, nInt(content), "I"); break; case SHR_INT_LIT8: to = nShr(vb, nInt(content), "I"); break; case USHR_INT_LIT8: to = nUshr(vb, nInt(content), "I"); break; default: throw new RuntimeException(); } x(nAssign(va, to)); } @Override public void visitStmt3R(Op op, int a, int b, int c) { Value va = locals[a]; Value vb = locals[b]; Value vc = locals[c]; switch (op) { case APUT: x(nAssign(nArray(vb, vc, TypeClass.IF.name), va)); break; case APUT_BOOLEAN: x(nAssign(nArray(vb, vc, "Z"), va)); break; case APUT_BYTE: x(nAssign(nArray(vb, vc, "B"), va)); break; case APUT_CHAR: x(nAssign(nArray(vb, vc, "C"), va)); break; case APUT_OBJECT: x(nAssign(nArray(vb, vc, "L"), va)); break; case APUT_SHORT: x(nAssign(nArray(vb, vc, "S"), va)); break; case APUT_WIDE: x(nAssign(nArray(vb, vc, TypeClass.JD.name), va)); break; case AGET: x(nAssign(va, nArray(vb, vc, TypeClass.IF.name))); break; case AGET_BOOLEAN: x(nAssign(va, nArray(vb, vc, "Z"))); break; case AGET_BYTE: x(nAssign(va, nArray(vb, vc, "B"))); break; case AGET_CHAR: x(nAssign(va, nArray(vb, vc, "C"))); break; case AGET_OBJECT: x(nAssign(va, nArray(vb, vc, "L"))); break; case AGET_SHORT: x(nAssign(va, nArray(vb, vc, "S"))); break; case AGET_WIDE: x(nAssign(va, nArray(vb, vc, TypeClass.JD.name))); break; case CMP_LONG: x(nAssign(va, nLCmp(vb, vc))); break; case CMPG_DOUBLE: x(nAssign(va, nDCmpg(vb, vc))); break; case CMPG_FLOAT: x(nAssign(va, nFCmpg(vb, vc))); break; case CMPL_DOUBLE: x(nAssign(va, nDCmpl(vb, vc))); break; case CMPL_FLOAT: x(nAssign(va, nFCmpl(vb, vc))); break; case ADD_DOUBLE: x(nAssign(va, nAdd(vb, vc, "D"))); break; case ADD_FLOAT: x(nAssign(va, nAdd(vb, vc, "F"))); break; case ADD_INT: x(nAssign(va, nAdd(vb, vc, "I"))); break; case ADD_LONG: x(nAssign(va, nAdd(vb, vc, "J"))); break; case SUB_DOUBLE: x(nAssign(va, nSub(vb, vc, "D"))); break; case SUB_FLOAT: x(nAssign(va, nSub(vb, vc, "F"))); break; // case RSUB_INT: // x(nAssign(va, nSub(vc, vb, "I"))); // break; case SUB_INT: x(nAssign(va, nSub(vb, vc, "I"))); break; case SUB_LONG: x(nAssign(va, nSub(vb, vc, "J"))); break; case MUL_DOUBLE: x(nAssign(va, nMul(vb, vc, "D"))); break; case MUL_FLOAT: x(nAssign(va, nMul(vb, vc, "F"))); break; case MUL_INT: x(nAssign(va, nMul(vb, vc, "I"))); break; case MUL_LONG: x(nAssign(va, nMul(vb, vc, "J"))); break; case DIV_DOUBLE: x(nAssign(va, nDiv(vb, vc, "D"))); break; case DIV_FLOAT: x(nAssign(va, nDiv(vb, vc, "F"))); break; case DIV_INT: x(nAssign(va, nDiv(vb, vc, "I"))); break; case DIV_LONG: x(nAssign(va, nDiv(vb, vc, "J"))); break; case REM_DOUBLE: x(nAssign(va, nRem(vb, vc, "D"))); break; case REM_FLOAT: x(nAssign(va, nRem(vb, vc, "F"))); break; case REM_INT: x(nAssign(va, nRem(vb, vc, "I"))); break; case REM_LONG: x(nAssign(va, nRem(vb, vc, "J"))); break; case AND_INT: x(nAssign(va, nAnd(vb, vc, TypeClass.ZI.name))); break; case AND_LONG: x(nAssign(va, nAnd(vb, vc, "J"))); break; case OR_INT: x(nAssign(va, nOr(vb, vc, TypeClass.ZI.name))); break; case OR_LONG: x(nAssign(va, nOr(vb, vc, "J"))); break; case XOR_INT: x(nAssign(va, nXor(vb, vc, TypeClass.ZI.name))); break; case XOR_LONG: x(nAssign(va, nXor(vb, vc, "J"))); break; case SHL_INT: x(nAssign(va, nShl(vb, vc, "I"))); break; case SHL_LONG: x(nAssign(va, nShl(vb, vc, "J"))); break; case SHR_INT: x(nAssign(va, nShr(vb, vc, "I"))); break; case SHR_LONG: x(nAssign(va, nShr(vb, vc, "J"))); break; case USHR_INT: x(nAssign(va, nUshr(vb, vc, "I"))); break; case USHR_LONG: x(nAssign(va, nUshr(vb, vc, "J"))); break; default: throw new RuntimeException(); } } @Override public void visitTypeStmt(Op op, int a, int b, String type) { switch (op) { case INSTANCE_OF: list.add(nAssign(locals[a], nInstanceOf(locals[b], type))); break; case NEW_ARRAY: list.add(nAssign(locals[a], nNewArray(type.substring(1), locals[b]))); break; case CHECK_CAST: list.add(nAssign(locals[a], nCheckCast(locals[a], type))); break; case NEW_INSTANCE: list.add(nAssign(locals[a], nNew(type))); break; default: throw new RuntimeException(); } } @Override public void visitFillArrayDataStmt(Op op, int ra, Object array) { x(nFillArrayData(locals[ra], nArrayValue(array))); } @Override public void visitConstStmt(Op op, int toReg, Object value) { switch (op) { case CONST: case CONST_16: case CONST_4: case CONST_HIGH16: x(nAssign(locals[toReg], nInt((Integer) value))); break; case CONST_WIDE: case CONST_WIDE_16: case CONST_WIDE_32: case CONST_WIDE_HIGH16: x(nAssign(locals[toReg], nLong((Long) value))); break; case CONST_CLASS: x(nAssign(locals[toReg], nType(((DexType) value).desc))); break; case CONST_STRING: case CONST_STRING_JUMBO: x(nAssign(locals[toReg], nString((String) value))); break; default: throw new RuntimeException(); } } /* * (non-Javadoc) * * @see com.googlecode.dex2jar.visitors.DexCodeVisitor#visitEnd() */ @Override public void visitEnd() { irMethod.locals.addAll(Arrays.asList(this.locals)); irMethod.locals.add(tmpLocal); this.locals = null; } @Override public void visitFieldStmt(Op op, int a, int b, Field field) { switch (op) { case IGET: case IGET_BOOLEAN: case IGET_BYTE: case IGET_CHAR: case IGET_OBJECT: case IGET_SHORT: case IGET_WIDE: list.add(nAssign(locals[a], nField(locals[b], field.getOwner(), field.getName(), field.getType()))); break; case IPUT: case IPUT_BOOLEAN: case IPUT_BYTE: case IPUT_CHAR: case IPUT_OBJECT: case IPUT_SHORT: case IPUT_WIDE: list.add(nAssign(nField(locals[b], field.getOwner(), field.getName(), field.getType()), locals[a])); break; case SGET: case SGET_BOOLEAN: case SGET_BYTE: case SGET_CHAR: case SGET_OBJECT: case SGET_SHORT: case SGET_WIDE: list.add(nAssign(locals[a], nStaticField(field.getOwner(), field.getName(), field.getType()))); break; case SPUT: case SPUT_BOOLEAN: case SPUT_BYTE: case SPUT_CHAR: case SPUT_OBJECT: case SPUT_SHORT: case SPUT_WIDE: list.add(nAssign(nStaticField(field.getOwner(), field.getName(), field.getType()), locals[a])); break; default: throw new RuntimeException(); } } @Override public void visitFilledNewArrayStmt(Op opc, int[] args, String type) { Local array = tmpLocal; String elem = type.substring(1); list.add(nAssign(array, nNewArray(elem, nInt(args.length)))); for (int i = 0; i < args.length; i++) { list.add(nAssign(nArray(array, nInt(i), elem), locals[args[i]])); } } @Override public void visitJumpStmt(Op op, int a, int b, DexLabel label) { switch (op) { case GOTO: case GOTO_16: case GOTO_32: x(nGoto(toLabelStmt(label))); break; case IF_EQ: x(nIf(Exprs.nEq(locals[a], locals[b], TypeClass.ZIL.name), toLabelStmt(label))); break; case IF_GE: x(nIf(Exprs.nGe(locals[a], locals[b], "I"), toLabelStmt(label))); break; case IF_GT: x(nIf(Exprs.nGt(locals[a], locals[b], "I"), toLabelStmt(label))); break; case IF_LE: x(nIf(Exprs.nLe(locals[a], locals[b], "I"), toLabelStmt(label))); break; case IF_LT: x(nIf(Exprs.nLt(locals[a], locals[b], "I"), toLabelStmt(label))); break; case IF_NE: x(nIf(Exprs.nNe(locals[a], locals[b], TypeClass.ZIL.name), toLabelStmt(label))); break; case IF_EQZ: x(nIf(Exprs.nEq(locals[a], nInt(0), TypeClass.ZIL.name), toLabelStmt(label))); break; case IF_GEZ: x(nIf(Exprs.nGe(locals[a], nInt(0), "I"), toLabelStmt(label))); break; case IF_GTZ: x(nIf(Exprs.nGt(locals[a], nInt(0), "I"), toLabelStmt(label))); break; case IF_LEZ: x(nIf(Exprs.nLe(locals[a], nInt(0), "I"), toLabelStmt(label))); break; case IF_LTZ: x(nIf(Exprs.nLt(locals[a], nInt(0), "I"), toLabelStmt(label))); break; case IF_NEZ: x(nIf(Exprs.nNe(locals[a], nInt(0), TypeClass.ZIL.name), toLabelStmt(label))); break; default: throw new RuntimeException(); } } @Override public void visitLabel(DexLabel label) { list.add(toLabelStmt(label)); } @Override public void visitSparseSwitchStmt(Op op, int aA, int[] cases, DexLabel[] labels) { LabelStmt[] lss = new LabelStmt[cases.length]; for (int i = 0; i < cases.length; i++) { lss[i] = toLabelStmt(labels[i]); } LabelStmt d = new LabelStmt(); x(nLookupSwitch(locals[aA], cases, lss, d)); x(d); } @Override public void visitMethodStmt(Op op, int[] args, Method method) { Value[] vs; if (args.length > 0) { int i = 0; List<Local> ps = new ArrayList<Local>(args.length); if (op == Op.INVOKE_STATIC || op == Op.INVOKE_STATIC_RANGE) { ; } else { ps.add(locals[args[i]]); i++; } for (String t : method.getParameterTypes()) { ps.add(locals[args[i]]); if (t.equals("J") || t.equals("D")) { i += 2; } else { i++; } } vs = ps.toArray(new Value[ps.size()]); } else { vs = new Value[0]; } Value invoke = null; switch (op) { case INVOKE_VIRTUAL_RANGE: case INVOKE_VIRTUAL: invoke = nInvokeVirtual(vs, method.getOwner(), method.getName(), method.getParameterTypes(), method.getReturnType()); break; case INVOKE_SUPER_RANGE: case INVOKE_DIRECT_RANGE: case INVOKE_SUPER: case INVOKE_DIRECT: invoke = nInvokeSpecial(vs, method.getOwner(), method.getName(), method.getParameterTypes(), method.getReturnType()); break; case INVOKE_STATIC_RANGE: case INVOKE_STATIC: invoke = nInvokeStatic(vs, method.getOwner(), method.getName(), method.getParameterTypes(), method.getReturnType()); break; case INVOKE_INTERFACE_RANGE: case INVOKE_INTERFACE: invoke = nInvokeInterface(vs, method.getOwner(), method.getName(), method.getParameterTypes(), method.getReturnType()); break; default: throw new RuntimeException(); } if ("V".equals(method.getReturnType())) { x(nVoidInvoke(invoke)); } else { x(nAssign(tmpLocal, invoke)); } } @Override public void visitStmt1R(Op op, int reg) { Local va = locals[reg]; switch (op) { case MONITOR_ENTER: x(nLock(va)); break; case MONITOR_EXIT: x(nUnLock(va)); break; case RETURN: case RETURN_WIDE: case RETURN_OBJECT: x(nReturn(va)); break; case THROW: x(nThrow(va)); break; case MOVE_RESULT: case MOVE_RESULT_WIDE: case MOVE_RESULT_OBJECT: if (lastIsInvokeOrFilledNewArray) { // right position x(nAssign(va, tmpLocal)); } else { // wrong position, replace with throw new RuntimeExceptoin("..."); System.err.println("WARN: find wrong position of " + op + " in method " + method); x(nThrow(nInvokeNew(new Value[] { nString("d2j: wrong position of " + op) }, new String[] { "Ljava/lang/String;" }, "Ljava/lang/RuntimeException;"))); } break; case MOVE_EXCEPTION: x(nIdentity(va, nExceptionRef("Ljava/lang/Throwable;"))); break; default: throw new RuntimeException(); } } @Override public void visitStmt2R(Op op, int a, int b) { Local va = locals[a]; Local vb = locals[b]; Value to = null; switch (op) { 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: to = vb; break; case ARRAY_LENGTH: to = nLength(vb); break; case ADD_DOUBLE_2ADDR: to = nAdd(va, vb, "D"); break; case ADD_FLOAT_2ADDR: to = nAdd(va, vb, "F"); break; case ADD_INT_2ADDR: to = nAdd(va, vb, "I"); break; case ADD_LONG_2ADDR: to = nAdd(va, vb, "J"); break; case SUB_DOUBLE_2ADDR: to = nSub(va, vb, "D"); break; case SUB_FLOAT_2ADDR: to = nSub(va, vb, "F"); break; case SUB_INT_2ADDR: to = nSub(va, vb, "I"); break; case SUB_LONG_2ADDR: to = nSub(va, vb, "J"); break; case MUL_DOUBLE_2ADDR: to = nMul(va, vb, "D"); break; case MUL_FLOAT_2ADDR: to = nMul(va, vb, "F"); break; case MUL_INT_2ADDR: to = nMul(va, vb, "I"); break; case MUL_LONG_2ADDR: to = nMul(va, vb, "J"); break; case DIV_DOUBLE_2ADDR: to = nDiv(va, vb, "D"); break; case DIV_FLOAT_2ADDR: to = nDiv(va, vb, "F"); break; case DIV_INT_2ADDR: to = nDiv(va, vb, "I"); break; case DIV_LONG_2ADDR: to = nDiv(va, vb, "J"); break; case REM_DOUBLE_2ADDR: to = nRem(va, vb, "D"); break; case REM_FLOAT_2ADDR: to = nRem(va, vb, "F"); break; case REM_INT_2ADDR: to = nRem(va, vb, "I"); break; case REM_LONG_2ADDR: to = nRem(va, vb, "J"); break; case AND_INT_2ADDR: to = nAnd(va, vb, TypeClass.ZI.name); break; case AND_LONG_2ADDR: to = nAnd(va, vb, "J"); break; case OR_INT_2ADDR: to = nOr(va, vb, TypeClass.ZI.name); break; case OR_LONG_2ADDR: to = nOr(va, vb, "J"); break; case XOR_INT_2ADDR: to = nXor(va, vb, TypeClass.ZI.name); break; case XOR_LONG_2ADDR: to = nXor(va, vb, "J"); break; case SHL_INT_2ADDR: to = nShl(va, vb, "I"); break; case SHL_LONG_2ADDR: to = nShl(va, vb, "J"); break; case SHR_INT_2ADDR: to = nShr(va, vb, "I"); break; case SHR_LONG_2ADDR: to = nShr(va, vb, "J"); break; case USHR_INT_2ADDR: to = nUshr(va, vb, "I"); break; case USHR_LONG_2ADDR: to = nUshr(va, vb, "J"); break; case NOT_INT: to = nNot(vb, "I"); break; case NOT_LONG: to = nNot(vb, "J"); break; case NEG_DOUBLE: to = nNeg(vb, "D"); break; case NEG_FLOAT: to = nNeg(vb, "F"); break; case NEG_INT: to = nNeg(vb, "I"); break; case NEG_LONG: to = nNeg(vb, "J"); break; case INT_TO_BYTE: to = nCast(vb, "I", "B"); break; case INT_TO_CHAR: to = nCast(vb, "I", "C"); break; case INT_TO_DOUBLE: to = nCast(vb, "I", "D"); break; case INT_TO_FLOAT: to = nCast(vb, "I", "F"); break; case INT_TO_LONG: to = nCast(vb, "I", "J"); break; case INT_TO_SHORT: to = nCast(vb, "I", "S"); break; case FLOAT_TO_DOUBLE: to = nCast(vb, "F", "D"); break; case FLOAT_TO_INT: to = nCast(vb, "F", "I"); break; case FLOAT_TO_LONG: to = nCast(vb, "F", "J"); break; case DOUBLE_TO_FLOAT: to = nCast(vb, "D", "F"); break; case DOUBLE_TO_INT: to = nCast(vb, "D", "I"); break; case DOUBLE_TO_LONG: to = nCast(vb, "D", "J"); break; case LONG_TO_DOUBLE: to = nCast(vb, "J", "D"); break; case LONG_TO_FLOAT: to = nCast(vb, "J", "F"); break; case LONG_TO_INT: to = nCast(vb, "J", "I"); break; default: throw new RuntimeException(); } x(nAssign(va, to)); } @Override public void visitStmt0R(Op op) { switch (op) { case RETURN_VOID: x(nReturnVoid()); break; case NOP: // ignore break; case BAD_OP: x(nThrow(nInvokeNew(new Value[] { nString("bad dex opcode") }, new String[] { "Ljava/lang/String;" }, "Ljava/lang/VerifyError;"))); break; default: throw new RuntimeException(); } } @Override public void visitPackedSwitchStmt(Op op, int aA, int first_case, DexLabel[] labels) { LabelStmt[] lss = new LabelStmt[labels.length]; for (int i = 0; i < labels.length; i++) { lss[i] = toLabelStmt(labels[i]); } LabelStmt d = new LabelStmt(); x(nTableSwitch(locals[aA], first_case, lss, d)); x(d); } @Override public void visitTryCatch(DexLabel start, DexLabel end, DexLabel[] handlers, String[] types) { LabelStmt xlabelStmts[] = new LabelStmt[types.length]; for (int i = 0; i < types.length; i++) { xlabelStmts[i] = toLabelStmt(handlers[i]); } irMethod.traps.add(new Trap(toLabelStmt(start), toLabelStmt(end), xlabelStmts, types)); } boolean lastIsInvokeOrFilledNewArray = false; public IrMethod convert(DexCodeNode codeNode) { if (codeNode.tryStmts != null) { for (DexCodeNode.DexStmtNode n : codeNode.tryStmts) { n.accept(this); } } if (codeNode.debugNode != null) { DexDebugVisitor ddv = this.visitDebug(); if (ddv != null) { codeNode.debugNode.accept(ddv); ddv.visitEnd(); } } lastIsInvokeOrFilledNewArray = false; if (codeNode.totalRegister >= 0) { this.visitRegister(codeNode.totalRegister); } for (DexCodeNode.DexStmtNode n : codeNode.stmts) { n.accept(this); if (n instanceof DexCodeNode.FilledNewArrayStmtNode) { lastIsInvokeOrFilledNewArray = true; } else if (n instanceof DexCodeNode.MethodStmtNode) { lastIsInvokeOrFilledNewArray = !((DexCodeNode.MethodStmtNode) n).method.getReturnType().equals("V"); } else if (!(n instanceof DexCodeNode.DexLabelStmtNode)) { lastIsInvokeOrFilledNewArray = false; } } visitEnd(); return irMethod; } }