Java tutorial
/* Soot - a J*va Optimization Framework * Copyright (C) 1997-2014 Raja Vallee-Rai and others * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package soot.asm; import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.tree.AbstractInsnNode.FIELD_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.IINC_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.INSN; import static org.objectweb.asm.tree.AbstractInsnNode.INT_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.JUMP_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.LABEL; import static org.objectweb.asm.tree.AbstractInsnNode.LDC_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.LOOKUPSWITCH_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.MULTIANEWARRAY_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.TABLESWITCH_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.TYPE_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.VAR_INSN; import static org.objectweb.asm.tree.AbstractInsnNode.LINE; import static org.objectweb.asm.tree.AbstractInsnNode.FRAME; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.IincInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.LookupSwitchInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MultiANewArrayInsnNode; import org.objectweb.asm.tree.TableSwitchInsnNode; import org.objectweb.asm.tree.TryCatchBlockNode; import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.VarInsnNode; import soot.ArrayType; import soot.Body; import soot.BooleanType; import soot.ByteType; import soot.CharType; import soot.DoubleType; import soot.FloatType; import soot.IntType; import soot.Local; import soot.LongType; import soot.MethodSource; import soot.PackManager; import soot.RefType; import soot.Scene; import soot.ShortType; import soot.SootClass; import soot.SootFieldRef; import soot.SootMethod; import soot.SootMethodRef; import soot.Trap; import soot.Type; import soot.Unit; import soot.UnitBox; import soot.UnknownType; import soot.Value; import soot.ValueBox; import soot.VoidType; import soot.jimple.AddExpr; import soot.jimple.ArrayRef; import soot.jimple.AssignStmt; import soot.jimple.BinopExpr; import soot.jimple.CastExpr; import soot.jimple.CaughtExceptionRef; import soot.jimple.ClassConstant; import soot.jimple.ConditionExpr; import soot.jimple.Constant; import soot.jimple.DefinitionStmt; import soot.jimple.DoubleConstant; import soot.jimple.FieldRef; import soot.jimple.FloatConstant; import soot.jimple.IdentityStmt; import soot.jimple.InstanceFieldRef; import soot.jimple.InstanceInvokeExpr; import soot.jimple.InstanceOfExpr; import soot.jimple.IntConstant; import soot.jimple.InvokeExpr; import soot.jimple.Jimple; import soot.jimple.JimpleBody; import soot.jimple.LongConstant; import soot.jimple.LookupSwitchStmt; import soot.jimple.MonitorStmt; import soot.jimple.NewArrayExpr; import soot.jimple.NewMultiArrayExpr; import soot.jimple.NullConstant; import soot.jimple.ReturnStmt; import soot.jimple.StringConstant; import soot.jimple.TableSwitchStmt; import soot.jimple.ThrowStmt; import soot.jimple.UnopExpr; import soot.util.Chain; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.HashBasedTable; import com.google.common.collect.Multimap; import com.google.common.collect.Table; /** * Generates Jimple bodies from bytecode. * * @author Aaloan Miftah */ final class AsmMethodSource implements MethodSource { private static final Operand DWORD_DUMMY = new Operand(null, null); /* -state fields- */ private int nextLocal; private Map<Integer, Local> locals; private Multimap<LabelNode, UnitBox> labels; private Map<AbstractInsnNode, Unit> units; private ArrayList<Operand> stack; private Map<AbstractInsnNode, StackFrame> frames; private Multimap<LabelNode, UnitBox> trapHandlers; private JimpleBody body; /* -const fields- */ private final int maxLocals; private final InsnList instructions; private final List<LocalVariableNode> localVars; private final List<TryCatchBlockNode> tryCatchBlocks; private final CastAndReturnInliner castAndReturnInliner = new CastAndReturnInliner(); AsmMethodSource(int maxLocals, InsnList insns, List<LocalVariableNode> localVars, List<TryCatchBlockNode> tryCatchBlocks) { this.maxLocals = maxLocals; this.instructions = insns; this.localVars = localVars; this.tryCatchBlocks = tryCatchBlocks; } private StackFrame getFrame(AbstractInsnNode insn) { StackFrame frame = frames.get(insn); if (frame == null) { frame = new StackFrame(this); frames.put(insn, frame); } return frame; } private Local getLocal(int idx) { if (idx >= maxLocals) throw new IllegalArgumentException("Invalid local index: " + idx); Integer i = idx; Local l = locals.get(i); if (l == null) { String name; if (localVars != null) { name = null; for (LocalVariableNode lvn : localVars) { if (lvn.index == idx) { name = lvn.name; break; } } /* normally for try-catch blocks */ if (name == null) name = "l" + idx; } else { name = "l" + idx; } l = Jimple.v().newLocal(name, UnknownType.v()); locals.put(i, l); } return l; } private void push(Operand opr) { stack.add(opr); } private void pushDual(Operand opr) { stack.add(DWORD_DUMMY); stack.add(opr); } private Operand peek() { return stack.get(stack.size() - 1); } private void push(Type t, Operand opr) { if (AsmUtil.isDWord(t)) pushDual(opr); else push(opr); } private Operand pop() { if (stack.isEmpty()) throw new RuntimeException("Stack underrun"); return stack.remove(stack.size() - 1); } private Operand popDual() { Operand o = pop(); Operand o2 = pop(); if (o2 != DWORD_DUMMY && o2 != o) throw new AssertionError("Not dummy operand, " + o2.value + " -- " + o.value); return o; } private Operand pop(Type t) { return AsmUtil.isDWord(t) ? popDual() : pop(); } private Operand popLocal(Operand o) { Value v = o.value; Local l = o.stack; if (l == null && !(v instanceof Local)) { l = o.stack = newStackLocal(); setUnit(o.insn, Jimple.v().newAssignStmt(l, v)); o.updateBoxes(); } return o; } private Operand popImmediate(Operand o) { Value v = o.value; Local l = o.stack; if (l == null && !(v instanceof Local) && !(v instanceof Constant)) { l = o.stack = newStackLocal(); setUnit(o.insn, Jimple.v().newAssignStmt(l, v)); o.updateBoxes(); } return o; } private Operand popStackConst(Operand o) { Value v = o.value; Local l = o.stack; if (l == null && !(v instanceof Constant)) { l = o.stack = newStackLocal(); setUnit(o.insn, Jimple.v().newAssignStmt(l, v)); o.updateBoxes(); } return o; } private Operand popLocal() { return popLocal(pop()); } private Operand popLocalDual() { return popLocal(popDual()); } @SuppressWarnings("unused") private Operand popLocal(Type t) { return AsmUtil.isDWord(t) ? popLocalDual() : popLocal(); } private Operand popImmediate() { return popImmediate(pop()); } private Operand popImmediateDual() { return popImmediate(popDual()); } private Operand popImmediate(Type t) { return AsmUtil.isDWord(t) ? popImmediateDual() : popImmediate(); } private Operand popStackConst() { return popStackConst(pop()); } private Operand popStackConstDual() { return popStackConst(popDual()); } @SuppressWarnings("unused") private Operand popStackConst(Type t) { return AsmUtil.isDWord(t) ? popStackConstDual() : popStackConst(); } void setUnit(AbstractInsnNode insn, Unit u) { Unit o = units.put(insn, u); if (o != null) throw new AssertionError(insn.getOpcode() + " already has a unit, " + o); } void mergeUnits(AbstractInsnNode insn, Unit u) { Unit prev = units.put(insn, u); if (prev != null) { Unit merged = new UnitContainer(prev, u); units.put(insn, merged); } } Local newStackLocal() { Integer idx = nextLocal++; Local l = Jimple.v().newLocal("$stack" + idx, UnknownType.v()); locals.put(idx, l); return l; } @SuppressWarnings("unchecked") <A extends Unit> A getUnit(AbstractInsnNode insn) { return (A) units.get(insn); } private void assignReadOps(Local l) { if (stack.isEmpty()) return; for (Operand opr : stack) { if (opr == DWORD_DUMMY || opr.stack != null || (l == null && opr.value instanceof Local)) continue; if (l != null && !opr.value.equivTo(l)) { List<ValueBox> uses = opr.value.getUseBoxes(); boolean noref = true; for (ValueBox use : uses) { Value val = use.getValue(); if (val.equivTo(l)) { noref = false; break; } } if (noref) continue; } int op = opr.insn.getOpcode(); if (l == null && op != GETFIELD && op != GETSTATIC && (op < IALOAD && op > SALOAD)) continue; Local stack = newStackLocal(); opr.stack = stack; AssignStmt as = Jimple.v().newAssignStmt(stack, opr.value); opr.updateBoxes(); setUnit(opr.insn, as); } } private void convertGetFieldInsn(FieldInsnNode insn) { StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; Type type; if (out == null) { SootClass declClass = Scene.v().getSootClass(AsmUtil.toQualifiedName(insn.owner)); type = AsmUtil.toJimpleType(insn.desc); Value val; SootFieldRef ref; if (insn.getOpcode() == GETSTATIC) { ref = Scene.v().makeFieldRef(declClass, insn.name, type, true); val = Jimple.v().newStaticFieldRef(ref); } else { Operand base = popLocal(); ref = Scene.v().makeFieldRef(declClass, insn.name, type, false); InstanceFieldRef ifr = Jimple.v().newInstanceFieldRef(base.stackOrValue(), ref); val = ifr; base.addBox(ifr.getBaseBox()); frame.in(base); frame.boxes(ifr.getBaseBox()); } opr = new Operand(insn, val); frame.out(opr); } else { opr = out[0]; type = opr.<FieldRef>value().getFieldRef().type(); if (insn.getOpcode() == GETFIELD) frame.mergeIn(pop()); } push(type, opr); } private void convertPutFieldInsn(FieldInsnNode insn) { boolean instance = insn.getOpcode() == PUTFIELD; StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr, rvalue; Type type; if (out == null) { SootClass declClass = Scene.v().getSootClass(AsmUtil.toQualifiedName(insn.owner)); type = AsmUtil.toJimpleType(insn.desc); Value val; SootFieldRef ref; rvalue = popImmediate(type); if (!instance) { ref = Scene.v().makeFieldRef(declClass, insn.name, type, true); val = Jimple.v().newStaticFieldRef(ref); frame.in(rvalue); } else { Operand base = popLocal(); ref = Scene.v().makeFieldRef(declClass, insn.name, type, false); InstanceFieldRef ifr = Jimple.v().newInstanceFieldRef(base.stackOrValue(), ref); val = ifr; base.addBox(ifr.getBaseBox()); frame.in(rvalue, base); } opr = new Operand(insn, val); frame.out(opr); AssignStmt as = Jimple.v().newAssignStmt(val, rvalue.stackOrValue()); rvalue.addBox(as.getRightOpBox()); if (!instance) { frame.boxes(as.getRightOpBox()); } else { frame.boxes(as.getRightOpBox(), ((InstanceFieldRef) val).getBaseBox()); } setUnit(insn, as); } else { opr = out[0]; type = opr.<FieldRef>value().getFieldRef().type(); rvalue = pop(type); if (!instance) { /* PUTSTATIC only needs one operand on the stack, the rvalue */ frame.mergeIn(rvalue); } else { /* PUTFIELD has a rvalue and a base */ frame.mergeIn(rvalue, pop()); } } /* * in case any static field or array is read from, and the static constructor * or the field this instruction writes to, modifies that field, write out any * previous read from field/array */ assignReadOps(null); } private void convertFieldInsn(FieldInsnNode insn) { int op = insn.getOpcode(); if (op == GETSTATIC || op == GETFIELD) convertGetFieldInsn(insn); else convertPutFieldInsn(insn); } private void convertIincInsn(IincInsnNode insn) { Local local = getLocal(insn.var); assignReadOps(local); if (!units.containsKey(insn)) { AddExpr add = Jimple.v().newAddExpr(local, IntConstant.v(insn.incr)); setUnit(insn, Jimple.v().newAssignStmt(local, add)); } } private void convertConstInsn(InsnNode insn) { int op = insn.getOpcode(); StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { Value v; if (op == ACONST_NULL) v = NullConstant.v(); else if (op >= ICONST_M1 && op <= ICONST_5) v = IntConstant.v(op - ICONST_0); else if (op == LCONST_0 || op == LCONST_1) v = LongConstant.v(op - LCONST_0); else if (op >= FCONST_0 && op <= FCONST_2) v = FloatConstant.v(op - FCONST_0); else if (op == DCONST_0 || op == DCONST_1) v = DoubleConstant.v(op - DCONST_0); else throw new AssertionError("Unknown constant opcode: " + op); opr = new Operand(insn, v); frame.out(opr); } else { opr = out[0]; } if (op == LCONST_0 || op == LCONST_1 || op == DCONST_0 || op == DCONST_1) { pushDual(opr); } else { push(opr); } } private void convertArrayLoadInsn(InsnNode insn) { StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { Operand indx = popImmediate(); Operand base = popImmediate(); ArrayRef ar = Jimple.v().newArrayRef(base.stackOrValue(), indx.stackOrValue()); indx.addBox(ar.getIndexBox()); base.addBox(ar.getBaseBox()); opr = new Operand(insn, ar); frame.in(indx, base); frame.boxes(ar.getIndexBox(), ar.getBaseBox()); frame.out(opr); } else { opr = out[0]; frame.mergeIn(pop(), pop()); } int op = insn.getOpcode(); if (op == DALOAD || op == LALOAD) pushDual(opr); else push(opr); } private void convertArrayStoreInsn(InsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LASTORE || op == DASTORE; StackFrame frame = getFrame(insn); if (!units.containsKey(insn)) { Operand valu = dword ? popImmediateDual() : popImmediate(); Operand indx = popImmediate(); Operand base = popLocal(); ArrayRef ar = Jimple.v().newArrayRef(base.stackOrValue(), indx.stackOrValue()); indx.addBox(ar.getIndexBox()); base.addBox(ar.getBaseBox()); AssignStmt as = Jimple.v().newAssignStmt(ar, valu.stackOrValue()); valu.addBox(as.getRightOpBox()); frame.in(valu, indx, base); frame.boxes(as.getRightOpBox(), ar.getIndexBox(), ar.getBaseBox()); setUnit(insn, as); } else { frame.mergeIn(dword ? popDual() : pop(), pop(), pop()); } } /* * Following version is more complex, * using stack frames as opposed to simply swapping */ /*StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand dup, dup2 = null, dupd, dupd2 = null; if (out == null) { dupd = popImmediate(); dup = new Operand(insn, dupd.stackOrValue()); if (dword) { dupd2 = peek(); if (dupd2 == DWORD_DUMMY) { pop(); dupd2 = dupd; } else { dupd2 = popImmediate(); } dup2 = new Operand(insn, dupd2.stackOrValue()); frame.out(dup, dup2); frame.in(dupd, dupd2); } else { frame.out(dup); frame.in(dupd); } } else { dupd = pop(); dup = out[0]; if (dword) { dupd2 = pop(); if (dupd2 == DWORD_DUMMY) dupd2 = dupd; dup2 = out[1]; frame.mergeIn(dupd, dupd2); } else { frame.mergeIn(dupd); } }*/ private void convertDupInsn(InsnNode insn) { int op = insn.getOpcode(); // Get the top stack value which we need in either case Operand dupd = popImmediate(); Operand dupd2 = null; // Some instructions allow operands that take two registers boolean dword = op == DUP2 || op == DUP2_X1 || op == DUP2_X2; if (dword) { if (peek() == DWORD_DUMMY) { pop(); dupd2 = dupd; } else dupd2 = popImmediate(); } if (op == DUP) { // val -> val, val push(dupd); push(dupd); } else if (op == DUP_X1) { // val2, val1 -> val1, val2, val1 // value1, value2 must not be of type double or long Operand o2 = popImmediate(); push(dupd); push(o2); push(dupd); } else if (op == DUP_X2) { // value3, value2, value1 -> value1, value3, value2, value1 Operand o2 = popImmediate(); Operand o3 = peek() == DWORD_DUMMY ? pop() : popImmediate(); push(dupd); push(o3); push(o2); push(dupd); } else if (op == DUP2) { // value2, value1 -> value2, value1, value2, value1 push(dupd2); push(dupd); push(dupd2); push(dupd); } else if (op == DUP2_X1) { // value3, value2, value1 -> value2, value1, value3, value2, value1 // Attention: value2 may be Operand o2 = popImmediate(); push(dupd2); push(dupd); push(o2); push(dupd2); push(dupd); } else if (op == DUP2_X2) { // (value4, value3), (value2, value1) -> (value2, value1), (value4, value3), (value2, value1) Operand o2 = popImmediate(); Operand o2h = peek() == DWORD_DUMMY ? pop() : popImmediate(); push(dupd2); push(dupd); push(o2h); push(o2); push(dupd2); push(dupd); } } private void convertBinopInsn(InsnNode insn) { int op = insn.getOpcode(); boolean dword = op == DADD || op == LADD || op == DSUB || op == LSUB || op == DMUL || op == LMUL || op == DDIV || op == LDIV || op == DREM || op == LREM || op == LSHL || op == LSHR || op == LUSHR || op == LAND || op == LOR || op == LXOR || op == LCMP || op == DCMPL || op == DCMPG; StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { Operand op2 = (dword && op != LSHL && op != LSHR && op != LUSHR) ? popImmediateDual() : popImmediate(); Operand op1 = dword ? popImmediateDual() : popImmediate(); Value v1 = op1.stackOrValue(); Value v2 = op2.stackOrValue(); BinopExpr binop; if (op >= IADD && op <= DADD) binop = Jimple.v().newAddExpr(v1, v2); else if (op >= ISUB && op <= DSUB) binop = Jimple.v().newSubExpr(v1, v2); else if (op >= IMUL && op <= DMUL) binop = Jimple.v().newMulExpr(v1, v2); else if (op >= IDIV && op <= DDIV) binop = Jimple.v().newDivExpr(v1, v2); else if (op >= IREM && op <= DREM) binop = Jimple.v().newRemExpr(v1, v2); else if (op >= ISHL && op <= LSHL) binop = Jimple.v().newShlExpr(v1, v2); else if (op >= ISHR && op <= LSHR) binop = Jimple.v().newShrExpr(v1, v2); else if (op >= IUSHR && op <= LUSHR) binop = Jimple.v().newUshrExpr(v1, v2); else if (op >= IAND && op <= LAND) binop = Jimple.v().newAndExpr(v1, v2); else if (op >= IOR && op <= LOR) binop = Jimple.v().newOrExpr(v1, v2); else if (op >= IXOR && op <= LXOR) binop = Jimple.v().newXorExpr(v1, v2); else if (op == LCMP) binop = Jimple.v().newCmpExpr(v1, v2); else if (op == FCMPL || op == DCMPL) binop = Jimple.v().newCmplExpr(v1, v2); else if (op == FCMPG || op == DCMPG) binop = Jimple.v().newCmpgExpr(v1, v2); else throw new AssertionError("Unknown binop: " + op); op1.addBox(binop.getOp1Box()); op2.addBox(binop.getOp2Box()); opr = new Operand(insn, binop); frame.in(op2, op1); frame.boxes(binop.getOp2Box(), binop.getOp1Box()); frame.out(opr); } else { opr = out[0]; if (dword) { if (op != LSHL && op != LSHR && op != LUSHR) frame.mergeIn(popDual(), popDual()); else frame.mergeIn(pop(), popDual()); } else { frame.mergeIn(pop(), pop()); } } if (dword && (op < LCMP || op > DCMPG)) pushDual(opr); else push(opr); } private void convertUnopInsn(InsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LNEG || op == DNEG; StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { Operand op1 = dword ? popImmediateDual() : popImmediate(); Value v1 = op1.stackOrValue(); UnopExpr unop; if (op >= INEG && op <= DNEG) unop = Jimple.v().newNegExpr(v1); else if (op == ARRAYLENGTH) unop = Jimple.v().newLengthExpr(v1); else throw new AssertionError("Unknown unop: " + op); op1.addBox(unop.getOpBox()); opr = new Operand(insn, unop); frame.in(op1); frame.boxes(unop.getOpBox()); frame.out(opr); } else { opr = out[0]; frame.mergeIn(dword ? popDual() : pop()); } if (dword) pushDual(opr); else push(opr); } private void convertPrimCastInsn(InsnNode insn) { int op = insn.getOpcode(); boolean tod = op == I2L || op == I2D || op == F2L || op == F2D || op == D2L || op == L2D; boolean fromd = op == D2L || op == L2D || op == D2I || op == L2I || op == D2F || op == L2F; StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { Type totype; if (op == I2L || op == F2L || op == D2L) totype = LongType.v(); else if (op == L2I || op == F2I || op == D2I) totype = IntType.v(); else if (op == I2F || op == L2F || op == D2F) totype = FloatType.v(); else if (op == I2D || op == L2D || op == F2D) totype = DoubleType.v(); else if (op == I2B) totype = ByteType.v(); else if (op == I2S) totype = ShortType.v(); else if (op == I2C) totype = CharType.v(); else throw new AssertionError("Unknonw prim cast op: " + op); Operand val = fromd ? popImmediateDual() : popImmediate(); CastExpr cast = Jimple.v().newCastExpr(val.stackOrValue(), totype); opr = new Operand(insn, cast); val.addBox(cast.getOpBox()); frame.in(val); frame.boxes(cast.getOpBox()); frame.out(opr); } else { opr = out[0]; frame.mergeIn(fromd ? popDual() : pop()); } if (tod) pushDual(opr); else push(opr); } private void convertReturnInsn(InsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LRETURN || op == DRETURN; StackFrame frame = getFrame(insn); if (!units.containsKey(insn)) { Operand val = dword ? popImmediateDual() : popImmediate(); ReturnStmt ret = Jimple.v().newReturnStmt(val.stackOrValue()); val.addBox(ret.getOpBox()); frame.in(val); frame.boxes(ret.getOpBox()); setUnit(insn, ret); } else { frame.mergeIn(dword ? popDual() : pop()); } } private void convertInsn(InsnNode insn) { int op = insn.getOpcode(); if (op == NOP) { /* * We can ignore NOP instructions, but * for completeness, we handle them */ if (!units.containsKey(insn)) units.put(insn, Jimple.v().newNopStmt()); } else if (op >= ACONST_NULL && op <= DCONST_1) { convertConstInsn(insn); } else if (op >= IALOAD && op <= SALOAD) { convertArrayLoadInsn(insn); } else if (op >= IASTORE && op <= SASTORE) { convertArrayStoreInsn(insn); } else if (op == POP) { popImmediate(); } else if (op == POP2) { popImmediate(); if (peek() == DWORD_DUMMY) pop(); else popImmediate(); } else if (op >= DUP && op <= DUP2_X2) { convertDupInsn((InsnNode) insn); } else if (op == SWAP) { Operand o1 = popImmediate(); Operand o2 = popImmediate(); push(o1); push(o2); } else if ((op >= IADD && op <= DREM) || (op >= ISHL && op <= LXOR) || (op >= LCMP && op <= DCMPG)) { convertBinopInsn((InsnNode) insn); } else if ((op >= INEG && op <= DNEG) || op == ARRAYLENGTH) { convertUnopInsn(insn); } else if (op >= I2L && op <= I2S) { convertPrimCastInsn(insn); } else if (op >= IRETURN && op <= ARETURN) { convertReturnInsn(insn); } else if (op == RETURN) { if (!units.containsKey(insn)) setUnit(insn, Jimple.v().newReturnVoidStmt()); } else if (op == ATHROW) { StackFrame frame = getFrame(insn); if (!units.containsKey(insn)) { Operand opr = popImmediate(); ThrowStmt ts = Jimple.v().newThrowStmt(opr.stackOrValue()); opr.addBox(ts.getOpBox()); frame.in(opr); frame.boxes(ts.getOpBox()); setUnit(insn, ts); } else { frame.mergeIn(pop()); } } else if (op == MONITORENTER || op == MONITOREXIT) { StackFrame frame = getFrame(insn); if (!units.containsKey(insn)) { Operand opr = popStackConst(); MonitorStmt ts = op == MONITORENTER ? Jimple.v().newEnterMonitorStmt(opr.stackOrValue()) : Jimple.v().newExitMonitorStmt(opr.stackOrValue()); opr.addBox(ts.getOpBox()); frame.in(opr); frame.boxes(ts.getOpBox()); setUnit(insn, ts); } else { frame.mergeIn(pop()); } } else { throw new AssertionError("Unknown insn op: " + op); } } private void convertIntInsn(IntInsnNode insn) { int op = insn.getOpcode(); StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { Value v; if (op == BIPUSH || op == SIPUSH) { v = IntConstant.v(insn.operand); } else { Type type; switch (insn.operand) { case T_BOOLEAN: type = BooleanType.v(); break; case T_CHAR: type = CharType.v(); break; case T_FLOAT: type = FloatType.v(); break; case T_DOUBLE: type = DoubleType.v(); break; case T_BYTE: type = ByteType.v(); break; case T_SHORT: type = ShortType.v(); break; case T_INT: type = IntType.v(); break; case T_LONG: type = LongType.v(); break; default: throw new AssertionError("Unknown NEWARRAY type!"); } Operand size = popImmediate(); NewArrayExpr anew = Jimple.v().newNewArrayExpr(type, size.stackOrValue()); size.addBox(anew.getSizeBox()); frame.in(size); frame.boxes(anew.getSizeBox()); v = anew; } opr = new Operand(insn, v); frame.out(opr); } else { opr = out[0]; if (op == NEWARRAY) frame.mergeIn(pop()); } push(opr); } private void convertJumpInsn(JumpInsnNode insn) { int op = insn.getOpcode(); if (op == GOTO) { if (!units.containsKey(insn)) { UnitBox box = Jimple.v().newStmtBox(null); labels.put(insn.label, box); setUnit(insn, Jimple.v().newGotoStmt(box)); } return; } /* must be ifX insn */ StackFrame frame = getFrame(insn); if (!units.containsKey(insn)) { Operand val = popImmediate(); Value v = val.stackOrValue(); ConditionExpr cond; if (op >= IF_ICMPEQ && op <= IF_ACMPNE) { Operand val1 = popImmediate(); Value v1 = val1.stackOrValue(); if (op == IF_ICMPEQ) cond = Jimple.v().newEqExpr(v1, v); else if (op == IF_ICMPNE) cond = Jimple.v().newNeExpr(v1, v); else if (op == IF_ICMPLT) cond = Jimple.v().newLtExpr(v1, v); else if (op == IF_ICMPGE) cond = Jimple.v().newGeExpr(v1, v); else if (op == IF_ICMPGT) cond = Jimple.v().newGtExpr(v1, v); else if (op == IF_ICMPLE) cond = Jimple.v().newLeExpr(v1, v); else if (op == IF_ACMPEQ) cond = Jimple.v().newEqExpr(v1, v); else if (op == IF_ACMPNE) cond = Jimple.v().newNeExpr(v1, v); else throw new AssertionError("Unknown if op: " + op); val1.addBox(cond.getOp1Box()); val.addBox(cond.getOp2Box()); frame.boxes(cond.getOp2Box(), cond.getOp1Box()); frame.in(val, val1); } else { if (op == IFEQ) cond = Jimple.v().newEqExpr(v, IntConstant.v(0)); else if (op == IFNE) cond = Jimple.v().newNeExpr(v, IntConstant.v(0)); else if (op == IFLT) cond = Jimple.v().newLtExpr(v, IntConstant.v(0)); else if (op == IFGE) cond = Jimple.v().newGeExpr(v, IntConstant.v(0)); else if (op == IFGT) cond = Jimple.v().newGtExpr(v, IntConstant.v(0)); else if (op == IFLE) cond = Jimple.v().newLeExpr(v, IntConstant.v(0)); else if (op == IFNULL) cond = Jimple.v().newEqExpr(v, NullConstant.v()); else if (op == IFNONNULL) cond = Jimple.v().newNeExpr(v, NullConstant.v()); else throw new AssertionError("Unknown if op: " + op); val.addBox(cond.getOp1Box()); frame.boxes(cond.getOp1Box()); frame.in(val); } UnitBox box = Jimple.v().newStmtBox(null); labels.put(insn.label, box); setUnit(insn, Jimple.v().newIfStmt(cond, box)); } else { if (op >= IF_ICMPEQ && op <= IF_ACMPNE) frame.mergeIn(pop(), pop()); else frame.mergeIn(pop()); } } private void convertLdcInsn(LdcInsnNode insn) { Object val = insn.cst; boolean dword = val instanceof Long || val instanceof Double; StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { Constant c; if (val instanceof Integer) c = IntConstant.v((Integer) val); else if (val instanceof Float) c = FloatConstant.v((Float) val); else if (val instanceof Long) c = LongConstant.v((Long) val); else if (val instanceof Double) c = DoubleConstant.v((Double) val); else if (val instanceof String) c = StringConstant.v(val.toString()); else if (val instanceof org.objectweb.asm.Type) c = ClassConstant.v(((org.objectweb.asm.Type) val).getInternalName()); else throw new AssertionError("Unknown constant type: " + val.getClass()); opr = new Operand(insn, c); frame.out(opr); } else { opr = out[0]; } if (dword) pushDual(opr); else push(opr); } private void convertLookupSwitchInsn(LookupSwitchInsnNode insn) { StackFrame frame = getFrame(insn); if (units.containsKey(insn)) { frame.mergeIn(pop()); return; } Operand key = popImmediate(); UnitBox dflt = Jimple.v().newStmtBox(null); List<UnitBox> targets = new ArrayList<UnitBox>(insn.labels.size()); labels.put(insn.dflt, dflt); for (LabelNode ln : insn.labels) { UnitBox box = Jimple.v().newStmtBox(null); targets.add(box); labels.put(ln, box); } List<IntConstant> keys = new ArrayList<IntConstant>(insn.keys.size()); for (Integer i : insn.keys) keys.add(IntConstant.v(i)); LookupSwitchStmt lss = Jimple.v().newLookupSwitchStmt(key.stackOrValue(), keys, targets, dflt); key.addBox(lss.getKeyBox()); frame.in(key); frame.boxes(lss.getKeyBox()); setUnit(insn, lss); } private void convertMethodInsn(MethodInsnNode insn) { int op = insn.getOpcode(); boolean instance = op != INVOKESTATIC; StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; Type returnType; if (out == null) { String clsName = AsmUtil.toQualifiedName(insn.owner); if (clsName.charAt(0) == '[') clsName = "java.lang.Object"; SootClass cls = Scene.v().getSootClass(clsName); List<Type> sigTypes = AsmUtil.toJimpleDesc(insn.desc); returnType = sigTypes.remove(sigTypes.size() - 1); SootMethodRef ref = Scene.v().makeMethodRef(cls, insn.name, sigTypes, returnType, !instance); int nrArgs = sigTypes.size(); Operand[] args = null; List<Value> argList = Collections.emptyList(); if (!instance) { args = nrArgs == 0 ? null : new Operand[nrArgs]; if (nrArgs != 0) { args = new Operand[nrArgs]; argList = new ArrayList<Value>(nrArgs); } } else { args = new Operand[nrArgs + 1]; if (nrArgs != 0) argList = new ArrayList<Value>(nrArgs); } while (nrArgs-- != 0) { args[nrArgs] = popImmediate(sigTypes.get(nrArgs)); argList.add(args[nrArgs].stackOrValue()); } if (argList.size() > 1) Collections.reverse(argList); if (instance) args[args.length - 1] = popLocal(); ValueBox[] boxes = args == null ? null : new ValueBox[args.length]; InvokeExpr invoke; if (!instance) { invoke = Jimple.v().newStaticInvokeExpr(ref, argList); } else { Local base = (Local) args[args.length - 1].stackOrValue(); InstanceInvokeExpr iinvoke; if (op == INVOKESPECIAL) iinvoke = Jimple.v().newSpecialInvokeExpr(base, ref, argList); else if (op == INVOKEVIRTUAL) iinvoke = Jimple.v().newVirtualInvokeExpr(base, ref, argList); else if (op == INVOKEVIRTUAL) iinvoke = Jimple.v().newVirtualInvokeExpr(base, ref, argList); else if (op == INVOKEINTERFACE) iinvoke = Jimple.v().newInterfaceInvokeExpr(base, ref, argList); else throw new AssertionError("Unknown invoke op:" + op); boxes[boxes.length - 1] = iinvoke.getBaseBox(); args[args.length - 1].addBox(boxes[boxes.length - 1]); invoke = iinvoke; } if (boxes != null) { for (int i = 0; i != sigTypes.size(); i++) { boxes[i] = invoke.getArgBox(i); args[i].addBox(boxes[i]); } frame.boxes(boxes); frame.in(args); } opr = new Operand(insn, invoke); frame.out(opr); } else { opr = out[0]; InvokeExpr expr = (InvokeExpr) opr.value; List<Type> types = expr.getMethodRef().parameterTypes(); Operand[] oprs; int nrArgs = types.size(); if (expr.getMethodRef().isStatic()) oprs = nrArgs == 0 ? null : new Operand[nrArgs]; else oprs = new Operand[nrArgs + 1]; if (oprs != null) { while (nrArgs-- != 0) { oprs[nrArgs] = pop(types.get(nrArgs)); } if (!expr.getMethodRef().isStatic()) oprs[oprs.length - 1] = pop(); frame.mergeIn(oprs); nrArgs = types.size(); } returnType = expr.getMethodRef().returnType(); } if (AsmUtil.isDWord(returnType)) pushDual(opr); else if (!(returnType instanceof VoidType)) push(opr); else if (!units.containsKey(insn)) setUnit(insn, Jimple.v().newInvokeStmt(opr.value)); /* * assign all read ops incase the method modifies any of the fields */ assignReadOps(null); } private void convertMultiANewArrayInsn(MultiANewArrayInsnNode insn) { StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { ArrayType t = (ArrayType) AsmUtil.toJimpleType(insn.desc); int dims = insn.dims; Operand[] sizes = new Operand[dims]; Value[] sizeVals = new Value[dims]; ValueBox[] boxes = new ValueBox[dims]; while (dims-- != 0) { sizes[dims] = popImmediate(); sizeVals[dims] = sizes[dims].stackOrValue(); } NewMultiArrayExpr nm = Jimple.v().newNewMultiArrayExpr(t, Arrays.asList(sizeVals)); for (int i = 0; i != boxes.length; i++) { ValueBox vb = nm.getSizeBox(i); sizes[i].addBox(vb); boxes[i] = vb; } frame.boxes(boxes); frame.in(sizes); opr = new Operand(insn, nm); frame.out(opr); } else { opr = out[0]; int dims = insn.dims; Operand[] sizes = new Operand[dims]; while (dims-- != 0) sizes[dims] = pop(); frame.mergeIn(sizes); } push(opr); } private void convertTableSwitchInsn(TableSwitchInsnNode insn) { StackFrame frame = getFrame(insn); if (units.containsKey(insn)) { frame.mergeIn(pop()); return; } Operand key = popImmediate(); UnitBox dflt = Jimple.v().newStmtBox(null); List<UnitBox> targets = new ArrayList<UnitBox>(insn.labels.size()); labels.put(insn.dflt, dflt); for (LabelNode ln : insn.labels) { UnitBox box = Jimple.v().newStmtBox(null); targets.add(box); labels.put(ln, box); } TableSwitchStmt tss = Jimple.v().newTableSwitchStmt(key.stackOrValue(), insn.min, insn.max, targets, dflt); key.addBox(tss.getKeyBox()); frame.in(key); frame.boxes(tss.getKeyBox()); setUnit(insn, tss); } private void convertTypeInsn(TypeInsnNode insn) { int op = insn.getOpcode(); StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { Type t = AsmUtil.toJimpleRefType(insn.desc); Value val; if (op == NEW) { val = Jimple.v().newNewExpr((RefType) t); } else { Operand op1 = popImmediate(); Value v1 = op1.stackOrValue(); ValueBox vb; if (op == ANEWARRAY) { NewArrayExpr expr = Jimple.v().newNewArrayExpr(t, v1); vb = expr.getSizeBox(); val = expr; } else if (op == CHECKCAST) { CastExpr expr = Jimple.v().newCastExpr(v1, t); vb = expr.getOpBox(); val = expr; } else if (op == INSTANCEOF) { InstanceOfExpr expr = Jimple.v().newInstanceOfExpr(v1, t); vb = expr.getOpBox(); val = expr; } else { throw new AssertionError("Unknown type op: " + op); } op1.addBox(vb); frame.in(op1); frame.boxes(vb); } opr = new Operand(insn, val); frame.out(opr); } else { opr = out[0]; if (op != NEW) frame.mergeIn(pop()); } push(opr); } private void convertVarLoadInsn(VarInsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LLOAD || op == DLOAD; StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand opr; if (out == null) { opr = new Operand(insn, getLocal(insn.var)); frame.out(opr); } else { opr = out[0]; } if (dword) pushDual(opr); else push(opr); } private void convertVarStoreInsn(VarInsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LSTORE || op == DSTORE; StackFrame frame = getFrame(insn); Operand opr = dword ? popDual() : pop(); Local local = getLocal(insn.var); if (!units.containsKey(insn)) { DefinitionStmt as = Jimple.v().newAssignStmt(local, opr.stackOrValue()); opr.addBox(as.getRightOpBox()); frame.boxes(as.getRightOpBox()); frame.in(opr); setUnit(insn, as); } else { frame.mergeIn(opr); } assignReadOps(local); } private void convertVarInsn(VarInsnNode insn) { int op = insn.getOpcode(); if (op >= ILOAD && op <= ALOAD) { convertVarLoadInsn(insn); } else if (op >= ISTORE && op <= ASTORE) { convertVarStoreInsn(insn); } else if (op == RET) { /* we handle it, even thought it should be removed */ if (!units.containsKey(insn)) setUnit(insn, Jimple.v().newRetStmt(getLocal(insn.var))); } else { throw new AssertionError("Unknown var op: " + op); } } private void convertLabel(LabelNode ln) { if (!trapHandlers.containsKey(ln)) return; StackFrame frame = getFrame(ln); Operand[] out = frame.out(); Operand opr; if (out == null) { CaughtExceptionRef ref = Jimple.v().newCaughtExceptionRef(); Local stack = newStackLocal(); DefinitionStmt as = Jimple.v().newIdentityStmt(stack, ref); opr = new Operand(ln, ref); opr.stack = stack; frame.out(opr); setUnit(ln, as); } else { opr = out[0]; } push(opr); } /* Conversion */ private final class Edge { /* edge endpoint */ final AbstractInsnNode insn; /* previous stacks at edge */ final LinkedList<Operand[]> prevStacks; /* current stack at edge */ ArrayList<Operand> stack; Edge(AbstractInsnNode insn, ArrayList<Operand> stack) { this.insn = insn; this.prevStacks = new LinkedList<Operand[]>(); this.stack = stack; } Edge(AbstractInsnNode insn) { this(insn, new ArrayList<Operand>(AsmMethodSource.this.stack)); } } private Table<AbstractInsnNode, AbstractInsnNode, Edge> edges; private ArrayDeque<Edge> conversionWorklist; private void addEdges(AbstractInsnNode cur, AbstractInsnNode tgt1, List<LabelNode> tgts) { int lastIdx = tgts == null ? -1 : tgts.size() - 1; Operand[] stackss = (new ArrayList<Operand>(stack)).toArray(new Operand[stack.size()]); AbstractInsnNode tgt = tgt1; int i = 0; tgt_loop: do { Edge edge = edges.get(cur, tgt); if (edge == null) { edge = new Edge(tgt); edge.prevStacks.add(stackss); edges.put(cur, tgt, edge); conversionWorklist.add(edge); continue; } if (edge.stack != null) { ArrayList<Operand> stackTemp = edge.stack; if (stackTemp.size() != stackss.length) { throw new AssertionError("Multiple un-equal stacks!"); } for (int j = 0; j != stackss.length; j++) { if (!stackTemp.get(j).equivTo(stackss[j])) throw new AssertionError("Multiple un-equal stacks!"); } continue; } for (Operand[] ps : edge.prevStacks) { if (Arrays.equals(ps, stackss)) continue tgt_loop; } edge.stack = new ArrayList<Operand>(stack); edge.prevStacks.add(stackss); conversionWorklist.add(edge); } while (i <= lastIdx && (tgt = tgts.get(i++)) != null); } private void convert() { ArrayDeque<Edge> worklist = new ArrayDeque<Edge>(); for (LabelNode ln : trapHandlers.keySet()) worklist.add(new Edge(ln, new ArrayList<Operand>())); worklist.add(new Edge(instructions.getFirst(), new ArrayList<Operand>())); conversionWorklist = worklist; edges = HashBasedTable.create(1, 1); do { Edge edge = worklist.pollLast(); AbstractInsnNode insn = edge.insn; stack = edge.stack; edge.stack = null; do { int type = insn.getType(); if (type == FIELD_INSN) { convertFieldInsn((FieldInsnNode) insn); } else if (type == IINC_INSN) { convertIincInsn((IincInsnNode) insn); } else if (type == INSN) { convertInsn((InsnNode) insn); int op = insn.getOpcode(); if ((op >= IRETURN && op <= RETURN) || op == ATHROW) { break; } } else if (type == INT_INSN) { convertIntInsn((IntInsnNode) insn); } else if (type == LDC_INSN) { convertLdcInsn((LdcInsnNode) insn); } else if (type == JUMP_INSN) { JumpInsnNode jmp = (JumpInsnNode) insn; convertJumpInsn(jmp); int op = jmp.getOpcode(); if (op == JSR) throw new UnsupportedOperationException("JSR!"); if (op != GOTO) { /* ifX opcode, i.e. two successors */ AbstractInsnNode next = insn.getNext(); addEdges(insn, next, Collections.singletonList(jmp.label)); } else { addEdges(insn, jmp.label, null); } break; } else if (type == LOOKUPSWITCH_INSN) { LookupSwitchInsnNode swtch = (LookupSwitchInsnNode) insn; convertLookupSwitchInsn(swtch); LabelNode dflt = swtch.dflt; addEdges(insn, dflt, swtch.labels); break; } else if (type == METHOD_INSN) { convertMethodInsn((MethodInsnNode) insn); } else if (type == MULTIANEWARRAY_INSN) { convertMultiANewArrayInsn((MultiANewArrayInsnNode) insn); } else if (type == TABLESWITCH_INSN) { TableSwitchInsnNode swtch = (TableSwitchInsnNode) insn; convertTableSwitchInsn(swtch); LabelNode dflt = swtch.dflt; addEdges(insn, dflt, swtch.labels); } else if (type == TYPE_INSN) { convertTypeInsn((TypeInsnNode) insn); } else if (type == VAR_INSN) { if (insn.getOpcode() == RET) throw new UnsupportedOperationException("RET!"); convertVarInsn((VarInsnNode) insn); } else if (type == LABEL) { convertLabel((LabelNode) insn); } else if (type == LINE || type == FRAME) { // we can ignore it } else throw new RuntimeException("Unknown instruction type: " + type); } while ((insn = insn.getNext()) != null); } while (!worklist.isEmpty()); conversionWorklist = null; edges = null; } private void emitLocals() { JimpleBody jb = body; SootMethod m = jb.getMethod(); Chain<Local> jbl = jb.getLocals(); Chain<Unit> jbu = jb.getUnits(); int iloc = 0; if (!m.isStatic()) { Local l = getLocal(iloc++); jbu.add(Jimple.v().newIdentityStmt(l, Jimple.v().newThisRef(m.getDeclaringClass().getType()))); } int nrp = 0; for (Object ot : m.getParameterTypes()) { Type t = (Type) ot; Local l = getLocal(iloc); jbu.add(Jimple.v().newIdentityStmt(l, Jimple.v().newParameterRef(t, nrp++))); if (AsmUtil.isDWord(t)) iloc += 2; else iloc++; } for (Local l : locals.values()) { jbl.add(l); } } private void emitTraps() { Chain<Trap> traps = body.getTraps(); SootClass throwable = Scene.v().getSootClass("java.lang.Throwable"); Map<LabelNode, Iterator<UnitBox>> handlers = new HashMap<LabelNode, Iterator<UnitBox>>( tryCatchBlocks.size()); for (TryCatchBlockNode tc : tryCatchBlocks) { UnitBox start = Jimple.v().newStmtBox(null); UnitBox end = Jimple.v().newStmtBox(null); Iterator<UnitBox> hitr = handlers.get(tc.handler); if (hitr == null) { hitr = trapHandlers.get(tc.handler).iterator(); handlers.put(tc.handler, hitr); } UnitBox handler = hitr.next(); SootClass cls = tc.type == null ? throwable : Scene.v().getSootClass(AsmUtil.toQualifiedName(tc.type)); Trap trap = Jimple.v().newTrap(cls, start, end, handler); traps.add(trap); labels.put(tc.start, start); labels.put(tc.end, end); } } private void emitUnits(Unit u) { if (u instanceof UnitContainer) { for (Unit uu : ((UnitContainer) u).units) emitUnits(uu); } else { body.getUnits().add(u); } } private void emitUnits() { AbstractInsnNode insn = instructions.getFirst(); ArrayDeque<LabelNode> labls = new ArrayDeque<LabelNode>(); while (insn != null) { // Save the label to assign it to the next real unit if (insn instanceof LabelNode) labls.add((LabelNode) insn); // Get the unit associated with the current instruction Unit u = units.get(insn); if (u == null) { insn = insn.getNext(); continue; } emitUnits(u); // If this is an exception handler, register the starting unit for it if (insn instanceof LabelNode && u instanceof IdentityStmt && ((IdentityStmt) u).getRightOp() instanceof CaughtExceptionRef) { // We directly place this label Collection<UnitBox> traps = trapHandlers.get((LabelNode) insn); for (UnitBox ub : traps) ub.setUnit(u); } // Register this unit for all targets of the labels ending up at it while (!labls.isEmpty()) { LabelNode ln = labls.poll(); Collection<UnitBox> boxes = labels.get(ln); if (boxes != null) { for (UnitBox box : boxes) { Unit uu = u; while (uu instanceof UnitContainer) uu = ((UnitContainer) u).units[0]; box.setUnit(uu); } } } insn = insn.getNext(); } /* set remaining labels & boxes to last unit of chain */ if (labls.isEmpty()) return; Unit end = Jimple.v().newNopStmt(); body.getUnits().add(end); while (!labls.isEmpty()) { LabelNode ln = labls.poll(); Collection<UnitBox> boxes = labels.get(ln); if (boxes != null) { for (UnitBox box : boxes) box.setUnit(end); } } } public Body getBody(SootMethod m, String phaseName) { if (!m.isConcrete()) return null; JimpleBody jb = Jimple.v().newBody(m); /* initialize */ int nrInsn = instructions.size(); nextLocal = maxLocals; locals = new HashMap<Integer, Local>(maxLocals + (maxLocals / 2)); labels = ArrayListMultimap.create(4, 1); units = new HashMap<AbstractInsnNode, Unit>(nrInsn); frames = new HashMap<AbstractInsnNode, StackFrame>(nrInsn); trapHandlers = ArrayListMultimap.create(tryCatchBlocks.size(), 1); body = jb; /* retrieve all trap handlers */ for (TryCatchBlockNode tc : tryCatchBlocks) trapHandlers.put(tc.handler, Jimple.v().newStmtBox(null)); /* convert instructions */ try { convert(); } catch (Throwable t) { throw new RuntimeException("Failed to convert " + m, t); } /* build body (add units, locals, traps, etc.) */ emitLocals(); emitTraps(); emitUnits(); /* clean up */ locals = null; labels = null; units = null; stack = null; frames = null; body = null; // Make sure to inline patterns of the form to enable proper variable // splitting and type assignment: // a = new A(); // goto l0; // l0: // b = (B) a; // return b; castAndReturnInliner.transform(jb); try { PackManager.v().getPack("jb").apply(jb); } catch (Throwable t) { throw new RuntimeException("Failed to apply jb to " + m, t); } return jb; } }