de.sanandrew.core.manpack.transformer.InstructionComparator.java Source code

Java tutorial

Introduction

Here is the source code for de.sanandrew.core.manpack.transformer.InstructionComparator.java

Source

/*******************************************************************************************************************
 * Authors:   SanAndreasP
 * Copyright: SanAndreasP
 * License:   Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
 *                http://creativecommons.org/licenses/by-nc-sa/4.0/
 *******************************************************************************************************************/
package de.sanandrew.core.manpack.transformer;

import org.objectweb.asm.tree.*;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import static org.objectweb.asm.tree.AbstractInsnNode.*;

public final class InstructionComparator {
    public static boolean fieldInsnEqual(FieldInsnNode insn1, FieldInsnNode insn2) {
        return insn1.owner.equals(insn2.owner) && insn1.name.equals(insn2.name) && insn1.desc.equals(insn2.desc);
    }

    public static InsnList getImportantList(InsnList list) {
        if (list.size() == 0) {
            return list;
        }

        HashMap<LabelNode, LabelNode> labels = new HashMap<>();

        for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
            if (insn instanceof LabelNode) {
                labels.put((LabelNode) insn, (LabelNode) insn);
            }
        }

        InsnList importantNodeList = new InsnList();

        for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
            if (insn instanceof LabelNode || insn instanceof LineNumberNode) {
                continue;
            }

            importantNodeList.add(insn.clone(labels));
        }
        return importantNodeList;
    }

    public static boolean iincInsnEqual(IincInsnNode node1, IincInsnNode node2) {
        return node1.var == node2.var && node1.incr == node2.incr;
    }

    public static boolean insnEqual(AbstractInsnNode node1, AbstractInsnNode node2) {
        if (node1.getType() != node2.getType()) {
            return false;
        } else if (node1.getOpcode() != node2.getOpcode()) {
            return false;
        }

        switch (node2.getType()) {
        case VAR_INSN:
            return varInsnEqual((VarInsnNode) node1, (VarInsnNode) node2);
        case TYPE_INSN:
            return typeInsnEqual((TypeInsnNode) node1, (TypeInsnNode) node2);
        case FIELD_INSN:
            return fieldInsnEqual((FieldInsnNode) node1, (FieldInsnNode) node2);
        case METHOD_INSN:
            return methodInsnEqual((MethodInsnNode) node1, (MethodInsnNode) node2);
        case LDC_INSN:
            return ldcInsnEqual((LdcInsnNode) node1, (LdcInsnNode) node2);
        case IINC_INSN:
            return iincInsnEqual((IincInsnNode) node1, (IincInsnNode) node2);
        case INT_INSN:
            return intInsnEqual((IntInsnNode) node1, (IntInsnNode) node2);
        default:
            return true;
        }
    }

    public static List<Integer> insnListFind(InsnList haystack, InsnList needle) {
        LinkedList<Integer> list = new LinkedList<>();

        for (int start = 0; start <= haystack.size() - needle.size(); start++) {
            if (insnListMatches(haystack, needle, start)) {
                list.add(start);
            }
        }

        return list;
    }

    public static List<AbstractInsnNode> insnListFindEnd(InsnList haystack, InsnList needle) {
        LinkedList<AbstractInsnNode> callNodes = new LinkedList<>();

        for (int callPoint : insnListFind(haystack, needle)) {
            callNodes.add(haystack.get(callPoint + needle.size() - 1));
        }
        return callNodes;
    }

    public static List<InsnListSection> insnListFindL(InsnList haystack, InsnList needle) {
        HashSet<LabelNode> controlFlowLabels = new HashSet<>();

        for (AbstractInsnNode insn = haystack.getFirst(); insn != null; insn = insn.getNext()) {
            switch (insn.getType()) {
            case 8:
            case 15:
                break;
            case 7:
                JumpInsnNode jinsn = (JumpInsnNode) insn;
                controlFlowLabels.add(jinsn.label);
                break;
            case 11:
                TableSwitchInsnNode tsinsn = (TableSwitchInsnNode) insn;
                for (LabelNode label : tsinsn.labels) {
                    controlFlowLabels.add(label);
                }
                break;
            case 12:
                LookupSwitchInsnNode lsinsn = (LookupSwitchInsnNode) insn;
                for (LabelNode label : lsinsn.labels) {
                    controlFlowLabels.add(label);
                }
                break;
            }
        }

        LinkedList<InsnListSection> list = new LinkedList<>();

        nextsection: for (int start = 0; start <= haystack.size() - needle.size(); start++) {
            InsnListSection section = insnListMatchesL(haystack, needle, start, controlFlowLabels);
            if (section != null) {
                for (InsnListSection asection : list) {
                    if (asection.last == section.last) {
                        continue nextsection;
                    }
                }

                list.add(section);
            }
        }

        return list;
    }

    public static List<AbstractInsnNode> insnListFindStart(InsnList haystack, InsnList needle) {
        LinkedList<AbstractInsnNode> callNodes = new LinkedList<>();

        for (int callPoint : insnListFind(haystack, needle)) {
            callNodes.add(haystack.get(callPoint));
        }
        return callNodes;
    }

    public static boolean insnListMatches(InsnList haystack, InsnList needle, int start) {
        if (haystack.size() - start < needle.size()) {
            return false;
        }

        for (int i = 0; i < needle.size(); i++) {
            if (!insnEqual(haystack.get(i + start), needle.get(i))) {
                return false;
            }
        }
        return true;
    }

    private static InsnListSection insnListMatchesL(InsnList haystack, InsnList needle, int start,
            HashSet<LabelNode> controlFlowLabels) {
        int h = start, n = 0;

        for (; h < haystack.size() && n < needle.size(); h++) {
            AbstractInsnNode insn = haystack.get(h);

            if (insn.getType() == 15) {
                continue;
            }
            if (insn.getType() == 8 && !controlFlowLabels.contains(insn)) {
                continue;
            }
            if (!insnEqual(haystack.get(h), needle.get(n))) {
                return null;
            }
            n++;
        }
        if (n != needle.size()) {
            return null;
        }

        return new InsnListSection(haystack, start, h - 1);
    }

    public static boolean intInsnEqual(IntInsnNode node1, IntInsnNode node2) {
        return node1.operand == -1 || node2.operand == -1 || node1.operand == node2.operand;

    }

    public static boolean ldcInsnEqual(LdcInsnNode insn1, LdcInsnNode insn2) {
        return insn1.cst.equals("~") || insn2.cst.equals("~") || insn1.cst.equals(insn2.cst);

    }

    public static boolean methodInsnEqual(MethodInsnNode insn1, MethodInsnNode insn2) {
        return insn1.owner.equals(insn2.owner) && insn1.name.equals(insn2.name) && insn1.desc.equals(insn2.desc);
    }

    public static boolean typeInsnEqual(TypeInsnNode insn1, TypeInsnNode insn2) {
        return insn1.desc.equals("~") || insn2.desc.equals("~") || insn1.desc.equals(insn2.desc);

    }

    public static boolean varInsnEqual(VarInsnNode insn1, VarInsnNode insn2) {
        return insn1.var == -1 || insn2.var == -1 || insn1.var == insn2.var;

    }

    public static class InsnListSection {
        public AbstractInsnNode first;

        public AbstractInsnNode last;

        public InsnListSection(InsnList haystack, int start, int end) {
            this.first = haystack.get(start);
            this.last = haystack.get(end);
        }
    }
}