package org.objectweb.asm.commons.cfg.tree.util; import org.objectweb.asm.Type; import org.objectweb.asm.commons.cfg.Block; import org.objectweb.asm.commons.cfg.tree.NodeTree; import org.objectweb.asm.commons.cfg.tree.node.*; import org.objectweb.asm.tree.*; import java.util.ArrayList; import java.util.List; import static org.objectweb.asm.Opcodes.*; //import org.nullbool.api.obfuscation.cfg.FlowBlock; /** * @author Tyler Sedlar */ public class TreeBuilder { public static final int[] CDS, PDS; static { CDS = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 4, 3, 3, 3, 3, 1, 2, 1, 2, 3, 2, 3, 4, 2, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 2, 4, 1, 2, 1, 2, 2, 3, 2, 3, 2, 3, 2, 4, 2, 4, 2, 4, 0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 4, 2, 2, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0}; PDS = new int[]{0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 4, 5, 6, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 2, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}; } public static TreeSize getTreeSize(AbstractInsnNode ain) { int c = 0, p = 0; if (ain instanceof InsnNode || ain instanceof IntInsnNode || ain instanceof VarInsnNode || ain instanceof JumpInsnNode || ain instanceof TableSwitchInsnNode || ain instanceof LookupSwitchInsnNode) { c = CDS[ain.opcode()]; p = PDS[ain.opcode()]; } else if (ain instanceof FieldInsnNode) { FieldInsnNode fin = (FieldInsnNode) ain; char d = fin.desc.charAt(0); switch (fin.opcode()) { case GETFIELD: { c = 1; p = d == 'D' || d == 'J' ? 2 : 1; break; } case GETSTATIC: { c = 0; p = d == 'D' || d == 'J' ? 2 : 1; break; } case PUTFIELD: { c = d == 'D' || d == 'J' ? 3 : 2; p = 0; break; } case PUTSTATIC: { c = d == 'D' || d == 'J' ? 2 : 1; p = 0; break; } default: { c = 0; p = 0; break; } } } else if (ain instanceof MethodInsnNode) { MethodInsnNode min = (MethodInsnNode) ain; int as = Type.getArgumentsAndReturnSizes(min.desc); c = (as >> 2) - (min.opcode() == INVOKEDYNAMIC || min.opcode() == INVOKESTATIC ? 1 : 0); p = as & 0x03; } else if (ain instanceof LdcInsnNode) { Object cst = ((LdcInsnNode) ain).cst; p = cst instanceof Double || cst instanceof Long ? 2 : 1; } else if (ain instanceof MultiANewArrayInsnNode) { c = ((MultiANewArrayInsnNode) ain).dims; p = 1; } return new TreeSize(c, p); } private static AbstractNode createNode(AbstractInsnNode ain, NodeTree tree, TreeSize size) { int opcode = ain.opcode(); if (ain instanceof IntInsnNode) { return new NumberNode(tree, ain, size.collapsing, size.producing); } else if (ain instanceof VarInsnNode) { return new VariableNode(tree, ain, size.collapsing, size.producing); } else if (ain instanceof JumpInsnNode) { return new JumpNode(tree, (JumpInsnNode) ain, size.collapsing, size.producing); } else if (ain instanceof FieldInsnNode) { return new FieldMemberNode(tree, ain, size.collapsing, size.producing); } else if (ain instanceof MethodInsnNode) { return new MethodMemberNode(tree, ain, size.collapsing, size.producing); } else if (ain instanceof LdcInsnNode) { Object cst = ((LdcInsnNode) ain).cst; if (cst instanceof Number) { return new NumberNode(tree, ain, size.collapsing, size.producing); } else { return new ConstantNode(tree, ain, size.collapsing, size.producing); } } else if (ain instanceof IincInsnNode) { return new IincNode(tree, ain, size.collapsing, size.producing); } else if (ain instanceof TypeInsnNode) { return new TypeNode(tree, ain, size.collapsing, size.producing); } else { if (opcode >= ICONST_M1 && opcode <= DCONST_1) { return new NumberNode(tree, ain, size.collapsing, size.producing); } else if (opcode >= I2L && opcode <= I2S) { return new ConversionNode(tree, ain, size.collapsing, size.producing); } else if (opcode >= IADD && opcode <= LXOR) { return new ArithmeticNode(tree, ain, size.collapsing, size.producing); } else { return new AbstractNode(tree, ain, size.collapsing, size.producing); } } } private int treeIndex = -1; private AbstractNode iterate(List<AbstractNode> nodes) { if (treeIndex < 0) { return null; } AbstractNode node = nodes.get(treeIndex--); if (node.collapsed == 0) { return node; } int c = node.collapsed; while (c != 0) { AbstractNode n = iterate(nodes); if (n == null) { break; } int op = n.opcode(); if (op == MONITOREXIT && node.opcode() == ATHROW) n.producing = 1; node.addFirst(n); int cr = c - n.producing; if (cr < 0) { node.producing += -cr; n.producing = 0; break; } c -= n.producing; n.producing = 0; } return node; } public long create = 0; public long iterate = 0; public NodeTree build(MethodNode mn) { NodeTree tree = new NodeTree(mn); List<AbstractNode> nodes = new ArrayList<>(); long start = System.nanoTime(); for (AbstractInsnNode ain : mn.instructions.toArray()) nodes.add(createNode(ain, tree, getTreeSize(ain))); long end = System.nanoTime(); create += (end - start); treeIndex = nodes.size() - 1; AbstractNode node; start = System.nanoTime(); while ((node = iterate(nodes)) != null) tree.addFirst(node); end = System.nanoTime(); iterate += (end - start); return tree; } public NodeTree build(Block block) { NodeTree tree = new NodeTree(block); List<AbstractNode> nodes = new ArrayList<>(); long start = System.nanoTime(); for (AbstractInsnNode ain : block.instructions) nodes.add(createNode(ain, tree, getTreeSize(ain))); long end = System.nanoTime(); create += (end - start); treeIndex = nodes.size() - 1; AbstractNode node; start = System.nanoTime(); while ((node = iterate(nodes)) != null) tree.addFirst(node); end = System.nanoTime(); iterate += (end - start); return tree; } // public NodeTree build(MethodNode method, FlowBlock block) { // NodeTree tree = new NodeTree(method); // List<AbstractNode> nodes = new ArrayList<>(); // long start = System.nanoTime(); // for (AbstractInsnNode ain : block.insns()) // nodes.add(createNode(ain, tree, getTreeSize(ain))); // long end = System.nanoTime(); // create += (end - start); // treeIndex = nodes.size() - 1; // AbstractNode node; // start = System.nanoTime(); // while ((node = iterate(nodes)) != null) // tree.addFirst(node); // end = System.nanoTime(); // iterate += (end - start); // return tree; // } }