Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.googlecode.d2j.converter.J2IRConverter Maven / Gradle / Ivy
package com.googlecode.d2j.converter;
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.stmt.*;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.Frame;
import org.objectweb.asm.tree.analysis.Interpreter;
import org.objectweb.asm.tree.analysis.Value;
import java.util.*;
import static org.objectweb.asm.Opcodes.*;
public class J2IRConverter {
Map map = new HashMap<>();
InsnList insnList;
int[] parentCount;
JvmFrame[] frames;
MethodNode methodNode;
IrMethod target;
List emitStmts[];
List preEmit = new ArrayList<>();
List currentEmit;
private J2IRConverter() {
}
public static IrMethod convert(String owner, MethodNode methodNode) throws AnalyzerException {
return new J2IRConverter().convert0(owner, methodNode);
}
LabelStmt getLabel(LabelNode labelNode) {
Label label = labelNode.getLabel();
LabelStmt ls = map.get(label);
if (ls == null) {
ls = Stmts.nLabel();
map.put(label, ls);
}
return ls;
}
void emit(Stmt stmt) {
currentEmit.add(stmt);
}
IrMethod populate(String owner, MethodNode source) {
IrMethod target = new IrMethod();
target.name = source.name;
target.owner = "L" + owner + ";";
target.ret = Type.getReturnType(source.desc).getDescriptor();
Type[] args = Type.getArgumentTypes(source.desc);
String sArgs[] = new String[args.length];
target.args = sArgs;
for (int i = 0; i < args.length; i++) {
sArgs[i] = args[i].getDescriptor();
}
target.isStatic = 0 != (source.access & Opcodes.ACC_STATIC);
return target;
}
IrMethod convert0(String owner, MethodNode methodNode) throws AnalyzerException {
this.methodNode = methodNode;
target = populate(owner, methodNode);
if (methodNode.instructions.size() == 0) {
return target;
}
insnList = methodNode.instructions;
BitSet[] exBranch = new BitSet[insnList.size()];
parentCount = new int[insnList.size()];
initParentCount(parentCount);
BitSet handlers = new BitSet(insnList.size());
if (methodNode.tryCatchBlocks != null) {
for (TryCatchBlockNode tcb : methodNode.tryCatchBlocks) {
target.traps.add(new Trap(getLabel(tcb.start), getLabel(tcb.end), new LabelStmt[]{getLabel(tcb.handler)},
new String[]{tcb.type == null ? null : Type.getObjectType(tcb.type).getDescriptor()}));
int handlerIdx = insnList.indexOf(tcb.handler);
handlers.set(handlerIdx);
for (AbstractInsnNode p = tcb.start.getNext(); p != tcb.end; p = p.getNext()) {
BitSet x = exBranch[insnList.indexOf(p)];
if (x == null) {
x = exBranch[insnList.indexOf(p)] = new BitSet(insnList.size());
}
x.set(handlerIdx);
parentCount[handlerIdx]++;
}
}
}
Interpreter interpreter = buildInterpreter();
frames = new JvmFrame[insnList.size()];
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++) {
AbstractInsnNode p = insnList.get(i);
if (access.get(i)) {
List es = emitStmts[i];
if (es != null) {
stmts.addAll(es);
}
} else {
if (p.getType() == AbstractInsnNode.LABEL) {
stmts.add(getLabel((LabelNode) p));
}
}
}
emitStmts = null;
Queue queue = new LinkedList<>();
for (int i1 = 0; i1 < frames.length; i1++) {
JvmFrame frame = frames[i1];
if (parentCount[i1] > 1 && frame != null && access.get(i1)) {
for (int j = 0; j < frame.getLocals(); j++) {
JvmValue v = frame.getLocal(j);
addToQueue(queue, v);
}
for (int j = 0; j < frame.getStackSize(); j++) {
addToQueue(queue, frame.getStack(j));
}
}
}
while (!queue.isEmpty()) {
JvmValue v = queue.poll();
getLocal(v);
if (v.parent != null) {
if (v.parent.local == null) {
queue.add(v.parent);
}
}
if (v.otherParent != null) {
for (JvmValue v2 : v.otherParent) {
if (v2.local == null) {
queue.add(v2);
}
}
}
}
Set phiValues = new HashSet<>();
List phiLabels = new ArrayList<>();
for (int i = 0; i < frames.length; i++) {
JvmFrame frame = frames[i];
if (parentCount[i] > 1 && frame != null && access.get(i)) {
AbstractInsnNode p = insnList.get(i);
LabelStmt labelStmt = getLabel((LabelNode) p);
List phis = new ArrayList<>();
for (int j = 0; j < frame.getLocals(); j++) {
JvmValue v = frame.getLocal(j);
addPhi(v, phiValues, phis);
}
for (int j = 0; j < frame.getStackSize(); j++) {
addPhi(frame.getStack(j), phiValues, phis);
}
labelStmt.phis = phis;
phiLabels.add(labelStmt);
}
}
if (phiLabels.size() > 0) {
target.phiLabels = phiLabels;
}
return target;
}
private void addPhi(JvmValue v, Set phiValues, List phis) {
if (v != null) {
if (v.local != null) {
if (v.parent != null) {
phiValues.add(getLocal(v.parent));
}
if (v.otherParent != null) {
for (JvmValue v2 : v.otherParent) {
phiValues.add(getLocal(v2));
}
}
if (phiValues.size() > 0) {
phis.add(Stmts.nAssign(v.local, Exprs.nPhi(phiValues.toArray(new com.googlecode.dex2jar.ir.expr.Value[phiValues.size()]))));
phiValues.clear();
}
}
}
}
private void addToQueue(Queue queue, JvmValue v) {
if (v != null) {
if (v.local != null) {
if (v.parent != null) {
if (v.parent.local == null) {
queue.add(v.parent);
}
}
if (v.otherParent != null) {
for (JvmValue v2 : v.otherParent) {
if (v2.local == null) {
queue.add(v2);
}
}
}
}
}
}
private void dfs(BitSet[] exBranch, BitSet handlers, BitSet access, Interpreter interpreter) throws AnalyzerException {
currentEmit = preEmit;
JvmFrame first = initFirstFrame(methodNode, target);
if (parentCount[0] > 1) {
merge(first, 0);
} else {
frames[0] = first;
}
Stack stack = new Stack<>();
stack.push(insnList.getFirst());
JvmFrame tmp = new JvmFrame(methodNode.maxLocals, methodNode.maxStack);
while (!stack.isEmpty()) {
AbstractInsnNode p = stack.pop();
int index = insnList.indexOf(p);
if (!access.get(index)) {
access.set(index);
} else {
continue;
}
JvmFrame frame = frames[index];
setCurrentEmit(index);
if (p.getType() == AbstractInsnNode.LABEL) {
emit(getLabel((LabelNode) p));
if (handlers.get(index)) {
Local ex = newLocal();
emit(Stmts.nIdentity(ex, Exprs.nExceptionRef("Ljava/lang/Throwable;")));
frame.clearStack();
frame.push(new JvmValue(1, ex));
}
}
BitSet ex = exBranch[index];
if (ex != null) {
for (int i = ex.nextSetBit(0); i >= 0; i = ex.nextSetBit(i + 1)) {
mergeEx(frame, i);
stack.push(insnList.get(i));
}
}
tmp.init(frame);
tmp.execute(p, interpreter);
int op = p.getOpcode();
if (p.getType() == AbstractInsnNode.JUMP_INSN) {
JumpInsnNode jump = (JumpInsnNode) p;
stack.push(jump.label);
merge(tmp, insnList.indexOf(jump.label));
}
if (op == Opcodes.TABLESWITCH || op == Opcodes.LOOKUPSWITCH) {
if (op == Opcodes.TABLESWITCH) {
TableSwitchInsnNode tsin = (TableSwitchInsnNode) p;
for (LabelNode label : tsin.labels) {
stack.push(label);
merge(tmp, insnList.indexOf(label));
}
stack.push(tsin.dflt);
merge(tmp, insnList.indexOf(tsin.dflt));
} else {
LookupSwitchInsnNode lsin = (LookupSwitchInsnNode) p;
for (LabelNode label : lsin.labels) {
stack.push(label);
merge(tmp, insnList.indexOf(label));
}
stack.push(lsin.dflt);
merge(tmp, insnList.indexOf(lsin.dflt));
}
}
if ((op >= Opcodes.GOTO && op <= Opcodes.RETURN) || op == Opcodes.ATHROW) {
// can't continue
} else {
stack.push(p.getNext());
merge(tmp, index + 1);
}
// cleanup frame it is useless
if (parentCount[index] <= 1) {
frames[index] = null;
}
}
}
private void setCurrentEmit(int index) {
currentEmit = emitStmts[index];
if (currentEmit == null) {
currentEmit = emitStmts[index] = new ArrayList<>(1);
}
}
private Interpreter buildInterpreter() {
return new Interpreter(Opcodes.ASM4) {
@Override
public JvmValue newValue(Type type) {
return null;
}
@Override
public JvmValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
switch (insn.getOpcode()) {
case ACONST_NULL:
return b(1, Exprs.nNull());
case ICONST_M1:
case ICONST_0:
case ICONST_1:
case ICONST_2:
case ICONST_3:
case ICONST_4:
case ICONST_5:
return b(1, Exprs.nInt(insn.getOpcode() - ICONST_0));
case LCONST_0:
case LCONST_1:
return b(2, Exprs.nLong(insn.getOpcode() - LCONST_0));
case FCONST_0:
case FCONST_1:
case FCONST_2:
return b(1, Exprs.nFloat(insn.getOpcode() - FCONST_0));
case DCONST_0:
case DCONST_1:
return b(2, Exprs.nDouble(insn.getOpcode() - DCONST_0));
case BIPUSH:
case SIPUSH:
return b(1, Exprs.nInt(((IntInsnNode) insn).operand));
case LDC:
Object cst = ((LdcInsnNode) insn).cst;
if (cst instanceof Integer) {
return b(1, Exprs.nInt((Integer) cst));
} else if (cst instanceof Float) {
return b(1, Exprs.nFloat((Float) cst));
} else if (cst instanceof Long) {
return b(2, Exprs.nLong((Long) cst));
} else if (cst instanceof Double) {
return b(2, Exprs.nDouble((Double) cst));
} else if (cst instanceof String) {
return b(1, Exprs.nString((String) cst));
} else if (cst instanceof Type) {
Type type = (Type) cst;
int sort = type.getSort();
if (sort == Type.OBJECT || sort == Type.ARRAY) {
return b(1, Exprs.nType(type.getDescriptor()));
} else if (sort == Type.METHOD) {
throw new UnsupportedOperationException("Not supported yet.");
} else {
throw new IllegalArgumentException("Illegal LDC constant " + cst);
}
} else if (cst instanceof Handle) {
throw new UnsupportedOperationException("Not supported yet.");
} else {
throw new IllegalArgumentException("Illegal LDC constant " + cst);
}
case JSR:
throw new UnsupportedOperationException("Not supported yet.");
case GETSTATIC:
FieldInsnNode fin = (FieldInsnNode) insn;
return b(Type.getType(fin.desc).getSize(), Exprs.nStaticField("L" + fin.owner + ";", fin.name,
fin.desc));
case NEW:
return b(1, Exprs.nNew("L" + ((TypeInsnNode) insn).desc + ";"));
default:
throw new Error("Internal error.");
}
}
@Override
public JvmValue copyOperation(AbstractInsnNode insn, JvmValue value) throws AnalyzerException {
return b(value.getSize(), getLocal(value));
}
@Override
public JvmValue unaryOperation(AbstractInsnNode insn, JvmValue value0) throws AnalyzerException {
Local local = value0 == null ? null : getLocal(value0);
switch (insn.getOpcode()) {
case INEG:
return b(1, Exprs.nNeg(local, "I"));
case IINC:
return b(1, Exprs.nAdd(local, Exprs.nInt(((IincInsnNode) insn).incr), "I"));
case L2I:
return b(1, Exprs.nCast(local, "J", "I"));
case F2I:
return b(1, Exprs.nCast(local, "F", "I"));
case D2I:
return b(1, Exprs.nCast(local, "D", "I"));
case I2B:
return b(1, Exprs.nCast(local, "I", "B"));
case I2C:
return b(1, Exprs.nCast(local, "I", "C"));
case I2S:
return b(1, Exprs.nCast(local, "I", "S"));
case FNEG:
return b(1, Exprs.nNeg(local, "F"));
case I2F:
return b(1, Exprs.nCast(local, "I", "F"));
case L2F:
return b(1, Exprs.nCast(local, "J", "F"));
case D2F:
return b(1, Exprs.nCast(local, "D", "F"));
case LNEG:
return b(2, Exprs.nNeg(local, "J"));
case I2L:
return b(2, Exprs.nCast(local, "I", "J"));
case F2L:
return b(2, Exprs.nCast(local, "F", "J"));
case D2L:
return b(2, Exprs.nCast(local, "D", "J"));
case DNEG:
return b(2, Exprs.nNeg(local, "D"));
case I2D:
return b(2, Exprs.nCast(local, "I", "D"));
case L2D:
return b(2, Exprs.nCast(local, "J", "D"));
case F2D:
return b(2, Exprs.nCast(local, "F", "D"));
case IFEQ:
emit(Stmts.nIf(Exprs.nEq(local, Exprs.nInt(0), "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IFNE:
emit(Stmts.nIf(Exprs.nNe(local, Exprs.nInt(0), "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IFLT:
emit(Stmts.nIf(Exprs.nLt(local, Exprs.nInt(0), "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IFGE:
emit(Stmts.nIf(Exprs.nGe(local, Exprs.nInt(0), "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IFGT:
emit(Stmts.nIf(Exprs.nGt(local, Exprs.nInt(0), "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IFLE:
emit(Stmts.nIf(Exprs.nLe(local, Exprs.nInt(0), "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case TABLESWITCH: {
TableSwitchInsnNode ts = (TableSwitchInsnNode) insn;
LabelStmt targets[] = new LabelStmt[ts.labels.size()];
for (int i = 0; i < ts.labels.size(); i++) {
targets[i] = getLabel((LabelNode) ts.labels.get(i));
}
emit(Stmts.nTableSwitch(local, ts.min, targets, getLabel(ts.dflt)));
return null;
}
case LOOKUPSWITCH: {
LookupSwitchInsnNode ls = (LookupSwitchInsnNode) insn;
LabelStmt targets[] = new LabelStmt[ls.labels.size()];
int[] lookupValues = new int[ls.labels.size()];
for (int i = 0; i < ls.labels.size(); i++) {
targets[i] = getLabel((LabelNode) ls.labels.get(i));
lookupValues[i] = (Integer) ls.keys.get(i);
}
emit(Stmts.nLookupSwitch(local, lookupValues, targets, getLabel(ls.dflt)));
return null;
}
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
// skip, move to returnOperation
return null;
case PUTSTATIC: {
FieldInsnNode fin = (FieldInsnNode) insn;
emit(Stmts.nAssign(Exprs.nStaticField("L" + fin.owner + ";", fin.name, fin.desc), local));
return null;
}
case GETFIELD: {
FieldInsnNode fin = (FieldInsnNode) insn;
Type fieldType = Type.getType(fin.desc);
return b(fieldType.getSize(), Exprs.nField(local, "L" + fin.owner + ";", fin.name, fin.desc));
}
case NEWARRAY:
switch (((IntInsnNode) insn).operand) {
case T_BOOLEAN:
return b(1, Exprs.nNewArray("Z", local));
case T_CHAR:
return b(1, Exprs.nNewArray("C", local));
case T_BYTE:
return b(1, Exprs.nNewArray("B", local));
case T_SHORT:
return b(1, Exprs.nNewArray("S", local));
case T_INT:
return b(1, Exprs.nNewArray("I", local));
case T_FLOAT:
return b(1, Exprs.nNewArray("F", local));
case T_DOUBLE:
return b(1, Exprs.nNewArray("D", local));
case T_LONG:
return b(1, Exprs.nNewArray("D", local));
default:
throw new AnalyzerException(insn, "Invalid array type");
}
case ANEWARRAY:
String desc = "L" + ((TypeInsnNode) insn).desc + ";";
return b(1, Exprs.nNewArray(desc, local));
case ARRAYLENGTH:
return b(1, Exprs.nLength(local));
case ATHROW:
emit(Stmts.nThrow(local));
return null;
case CHECKCAST:
String orgDesc = ((TypeInsnNode) insn).desc;
desc = orgDesc.startsWith("[") ? orgDesc : ("L" + orgDesc + ";");
return b(1, Exprs.nCheckCast(local, desc));
case INSTANCEOF:
return b(1, Exprs.nInstanceOf(local, "L" + ((TypeInsnNode) insn).desc + ";"));
case MONITORENTER:
emit(Stmts.nLock(local));
return null;
case MONITOREXIT:
emit(Stmts.nUnLock(local));
return null;
case IFNULL:
emit(Stmts.nIf(Exprs.nEq(local, Exprs.nNull(), "L"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IFNONNULL:
emit(Stmts.nIf(Exprs.nNe(local, Exprs.nNull(), "L"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case GOTO: // special case
emit(Stmts.nGoto(getLabel(((JumpInsnNode) insn).label)));
return null;
default:
throw new Error("Internal error.");
}
}
JvmValue b(int size, com.googlecode.dex2jar.ir.expr.Value value) {
Local local = newLocal();
emit(Stmts.nAssign(local, value));
return new JvmValue(size, local);
}
@Override
public JvmValue binaryOperation(AbstractInsnNode insn, JvmValue value10, JvmValue value20)
throws AnalyzerException {
Local local1 = getLocal(value10);
Local local2 = getLocal(value20);
switch (insn.getOpcode()) {
case IALOAD:
return b(1, Exprs.nArray(local1, local2, "I"));
case BALOAD:
return b(1, Exprs.nArray(local1, local2, "B"));
case CALOAD:
return b(1, Exprs.nArray(local1, local2, "C"));
case SALOAD:
return b(1, Exprs.nArray(local1, local2, "S"));
case FALOAD:
return b(1, Exprs.nArray(local1, local2, "F"));
case AALOAD:
return b(1, Exprs.nArray(local1, local2, "L"));
case DALOAD:
return b(1, Exprs.nArray(local1, local2, "D"));
case LALOAD:
return b(1, Exprs.nArray(local1, local2, "J"));
case IADD:
return b(1, Exprs.nAdd(local1, local2, "I"));
case ISUB:
return b(1, Exprs.nSub(local1, local2, "I"));
case IMUL:
return b(1, Exprs.nMul(local1, local2, "I"));
case IDIV:
return b(1, Exprs.nDiv(local1, local2, "I"));
case IREM:
return b(1, Exprs.nRem(local1, local2, "I"));
case ISHL:
return b(1, Exprs.nShl(local1, local2, "I"));
case ISHR:
return b(1, Exprs.nShr(local1, local2, "I"));
case IUSHR:
return b(1, Exprs.nUshr(local1, local2, "I"));
case IAND:
return b(1, Exprs.nAnd(local1, local2, "I"));
case IOR:
return b(1, Exprs.nOr(local1, local2, "I"));
case IXOR:
return b(1, Exprs.nXor(local1, local2, "I"));
case FADD:
return b(1, Exprs.nAdd(local1, local2, "F"));
case FSUB:
return b(1, Exprs.nSub(local1, local2, "F"));
case FMUL:
return b(1, Exprs.nMul(local1, local2, "F"));
case FDIV:
return b(1, Exprs.nDiv(local1, local2, "F"));
case FREM:
return b(1, Exprs.nRem(local1, local2, "F"));
case LADD:
return b(2, Exprs.nAdd(local1, local2, "J"));
case LSUB:
return b(2, Exprs.nSub(local1, local2, "J"));
case LMUL:
return b(2, Exprs.nMul(local1, local2, "J"));
case LDIV:
return b(2, Exprs.nDiv(local1, local2, "J"));
case LREM:
return b(2, Exprs.nRem(local1, local2, "J"));
case LSHL:
return b(2, Exprs.nShl(local1, local2, "J"));
case LSHR:
return b(2, Exprs.nShr(local1, local2, "J"));
case LUSHR:
return b(2, Exprs.nUshr(local1, local2, "J"));
case LAND:
return b(2, Exprs.nAnd(local1, local2, "J"));
case LOR:
return b(2, Exprs.nOr(local1, local2, "J"));
case LXOR:
return b(2, Exprs.nXor(local1, local2, "J"));
case DADD:
return b(2, Exprs.nAdd(local1, local2, "D"));
case DSUB:
return b(2, Exprs.nSub(local1, local2, "D"));
case DMUL:
return b(2, Exprs.nMul(local1, local2, "D"));
case DDIV:
return b(2, Exprs.nDiv(local1, local2, "D"));
case DREM:
return b(2, Exprs.nRem(local1, local2, "D"));
case LCMP:
return b(2, Exprs.nLCmp(local1, local2));
case FCMPL:
return b(1, Exprs.nFCmpl(local1, local2));
case FCMPG:
return b(1, Exprs.nFCmpg(local1, local2));
case DCMPL:
return b(2, Exprs.nDCmpl(local1, local2));
case DCMPG:
return b(2, Exprs.nDCmpg(local1, local2));
case IF_ICMPEQ:
emit(Stmts.nIf(Exprs.nEq(local1, local2, "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IF_ICMPNE:
emit(Stmts.nIf(Exprs.nNe(local1, local2, "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IF_ICMPLT:
emit(Stmts.nIf(Exprs.nLt(local1, local2, "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IF_ICMPGE:
emit(Stmts.nIf(Exprs.nGe(local1, local2, "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IF_ICMPGT:
emit(Stmts.nIf(Exprs.nGt(local1, local2, "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IF_ICMPLE:
emit(Stmts.nIf(Exprs.nLe(local1, local2, "I"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IF_ACMPEQ:
emit(Stmts.nIf(Exprs.nEq(local1, local2, "L"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case IF_ACMPNE:
emit(Stmts.nIf(Exprs.nNe(local1, local2, "L"),
getLabel(((JumpInsnNode) insn).label)));
return null;
case PUTFIELD:
FieldInsnNode fin = (FieldInsnNode) insn;
emit(Stmts.nAssign(Exprs.nField(local1, "L" + fin.owner + ";", fin.name, fin.desc), local2));
return null;
default:
throw new Error("Internal error.");
}
}
@Override
public JvmValue ternaryOperation(AbstractInsnNode insn, JvmValue value1, JvmValue value2, JvmValue value3)
throws AnalyzerException {
Local local1 = getLocal(value1);
Local local2 = getLocal(value2);
Local local3 = getLocal(value3);
switch (insn.getOpcode()) {
case IASTORE:
emit(Stmts.nAssign(Exprs.nArray(local1, local2, "I"),
local3));
break;
case LASTORE:
emit(Stmts.nAssign(Exprs.nArray(local1, local2, "J"),
local3));
break;
case FASTORE:
emit(Stmts.nAssign(Exprs.nArray(local1, local2, "F"),
local3));
break;
case DASTORE:
emit(Stmts.nAssign(Exprs.nArray(local1, local2, "D"),
local3));
break;
case AASTORE:
emit(Stmts.nAssign(Exprs.nArray(local1, local2, "L"),
local3));
break;
case BASTORE:
emit(Stmts.nAssign(Exprs.nArray(local1, local2, "B"),
local3));
break;
case CASTORE:
emit(Stmts.nAssign(Exprs.nArray(local1, local2, "C"),
local3));
break;
case SASTORE:
emit(Stmts.nAssign(Exprs.nArray(local1, local2, "S"),
local3));
break;
}
return null;
}
public String[] toDescArray(Type[] ts) {
String[] ds = new String[ts.length];
for (int i = 0; i < ts.length; i++) {
ds[i] = ts[i].getDescriptor();
}
return ds;
}
@Override
public JvmValue naryOperation(AbstractInsnNode insn, List extends JvmValue> xvalues) throws AnalyzerException {
com.googlecode.dex2jar.ir.expr.Value values[] = new com.googlecode.dex2jar.ir.expr.Value[xvalues.size()];
for (int i = 0; i < xvalues.size(); i++) {
values[i] = getLocal(xvalues.get(i));
}
if (insn.getOpcode() == MULTIANEWARRAY) {
throw new UnsupportedOperationException("Not supported yet.");
} else {
MethodInsnNode mi = (MethodInsnNode) insn;
com.googlecode.dex2jar.ir.expr.Value v = null;
String ret = Type.getReturnType(mi.desc).getDescriptor();
String owner = "L" + mi.owner + ";";
String ps[] = toDescArray(Type.getArgumentTypes(mi.desc));
switch (insn.getOpcode()) {
case INVOKEVIRTUAL:
v = Exprs.nInvokeVirtual(values, owner, mi.name, ps, ret);
break;
case INVOKESPECIAL:
v = Exprs.nInvokeSpecial(values, owner, mi.name, ps, ret);
break;
case INVOKESTATIC:
v = Exprs.nInvokeStatic(values, owner, mi.name, ps, ret);
break;
case INVOKEINTERFACE:
v = Exprs.nInvokeInterface(values, owner, mi.name, ps, ret);
break;
case INVOKEDYNAMIC:
throw new UnsupportedOperationException("Not supported yet.");
}
if ("V".equals(ret)) {
emit(Stmts.nVoidInvoke(v));
return null;
} else {
return b(Type.getReturnType(mi.desc).getSize(), v);
}
}
}
@Override
public JvmValue merge(JvmValue v, JvmValue w) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void returnOperation(AbstractInsnNode insn, JvmValue value, JvmValue expected) throws AnalyzerException {
switch (insn.getOpcode()) {
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
emit(Stmts.nReturn(getLocal(value)));
break;
case RETURN:
emit(Stmts.nReturnVoid());
break;
}
}
};
}
Local getLocal(JvmValue value) {
Local local = value.local;
if (local == null) {
local = value.local = newLocal();
}
return local;
}
private void initParentCount(int[] parentCount) {
parentCount[0] = 1;
for (AbstractInsnNode p = insnList.getFirst(); p != null; p = p.getNext()) {
if (p.getType() == AbstractInsnNode.JUMP_INSN) {
JumpInsnNode jump = (JumpInsnNode) p;
parentCount[insnList.indexOf(jump.label)]++;
}
int op = p.getOpcode();
if (op == Opcodes.TABLESWITCH || op == Opcodes.LOOKUPSWITCH) {
if (op == Opcodes.TABLESWITCH) {
TableSwitchInsnNode tsin = (TableSwitchInsnNode) p;
for (LabelNode label : tsin.labels) {
parentCount[insnList.indexOf(label)]++;
}
parentCount[insnList.indexOf(tsin.dflt)]++;
} else {
LookupSwitchInsnNode lsin = (LookupSwitchInsnNode) p;
for (LabelNode label : lsin.labels) {
parentCount[insnList.indexOf(label)]++;
}
parentCount[insnList.indexOf(lsin.dflt)]++;
}
}
if ((op >= Opcodes.GOTO && op <= Opcodes.RETURN) || op == Opcodes.ATHROW) {
// can't continue
} else {
AbstractInsnNode next = p.getNext();
if(next!=null) {
parentCount[insnList.indexOf(p.getNext())]++;
}
}
}
}
private void mergeEx(JvmFrame src, int dst) {
JvmFrame distFrame = frames[dst];
if (distFrame == null) {
distFrame = frames[dst] = new JvmFrame(methodNode.maxLocals, methodNode.maxStack);
}
for (int i = 0; i < src.getLocals(); i++) {
JvmValue p = src.getLocal(i);
JvmValue q = distFrame.getLocal(i);
if (p != null) {
if (q == null) {
q = new JvmValue(p.getSize());
distFrame.setLocal(i, q);
}
relate(p, q);
}
}
}
private void merge(JvmFrame src, int dst) {
JvmFrame distFrame = frames[dst];
if (distFrame == null) {
distFrame = frames[dst] = new JvmFrame(methodNode.maxLocals, methodNode.maxStack);
}
if (parentCount[dst] > 1) {
for (int i = 0; i < src.getLocals(); i++) {
JvmValue p = src.getLocal(i);
JvmValue q = distFrame.getLocal(i);
if (p != null) {
if (q == null) {
q = new JvmValue(p.getSize());
distFrame.setLocal(i, q);
}
relate(p, q);
}
}
if (src.getStackSize() > 0) {
if (distFrame.getStackSize() == 0) {
for (int i = 0; i < src.getStackSize(); i++) {
distFrame.push(new JvmValue(src.getStack(i).getSize()));
}
} else if (distFrame.getStackSize() != src.getStackSize()) {
throw new RuntimeException("stack not balanced");
}
for (int i = 0; i < src.getStackSize(); i++) {
JvmValue p = src.getStack(i);
JvmValue q = distFrame.getStack(i);
relate(p, q);
}
}
} else {
distFrame.init(src);
}
}
private void relate(JvmValue parent, JvmValue child) {
if (child.parent == null) {
child.parent = parent;
} else if (child.parent == parent) {
//
} else {
if (child.otherParent == null) {
child.otherParent = new HashSet<>(5);
}
child.otherParent.add(parent);
}
}
private JvmFrame initFirstFrame(MethodNode methodNode, IrMethod target) {
JvmFrame first = new JvmFrame(methodNode.maxLocals, methodNode.maxStack);
int x = 0;
if (!target.isStatic) {// not static
Local thiz = newLocal();
emit(Stmts.nIdentity(thiz, Exprs.nThisRef(target.owner)));
first.setLocal(x++, new JvmValue(1, thiz));
}
for (int i = 0; i < target.args.length; i++) {
Local p = newLocal();
emit(Stmts.nIdentity(p, Exprs.nParameterRef(target.args[i], i)));
int sizeOfType = sizeOfType(target.args[i]);
first.setLocal(x, new JvmValue(sizeOfType, p));
x += sizeOfType;
}
return first;
}
private int sizeOfType(String arg) {
switch (arg.charAt(0)) {
case 'J':
case 'D':
return 2;
default:
return 1;
}
}
private Local newLocal() {
Local thiz = Exprs.nLocal(target.locals.size());
target.locals.add(thiz);
return thiz;
}
static class JvmFrame extends Frame {
public JvmFrame(int nLocals, int nStack) {
super(nLocals, nStack);
}
@Override
public void execute(AbstractInsnNode insn, Interpreter interpreter) throws AnalyzerException {
if (insn.getType() == AbstractInsnNode.FRAME || insn.getType() == AbstractInsnNode.LINE || insn.getType() == AbstractInsnNode.LABEL) {
return;
}
if (insn.getOpcode() == Opcodes.RETURN) {
interpreter.returnOperation(insn, null, null);
} else if (insn.getOpcode() == Opcodes.GOTO) {
interpreter.unaryOperation(insn, null);
} else if (insn.getOpcode() == RET) {
throw new RuntimeException("not support yet!");
} else {
super.execute(insn, interpreter);
}
}
}
public static class JvmValue implements Value {
private final int size;
public JvmValue parent;
public Set otherParent;
Local local;
public JvmValue(int size, Local local) {
this.size = size;
this.local = local;
}
public JvmValue(int size) {
this.size = size;
}
@Override
public int getSize() {
return size;
}
}
}