package org.openrs2.deob.bytecode.analysis import org.jgrapht.Graph import org.jgrapht.graph.DefaultEdge import org.jgrapht.graph.EdgeReversedGraph import org.objectweb.asm.tree.AbstractInsnNode import org.objectweb.asm.tree.MethodNode import org.openrs2.util.collect.UniqueQueue public abstract class DataFlowAnalyzer(owner: String, private val method: MethodNode, backwards: Boolean = false) { private val graph: Graph private val inSets = mutableMapOf() private val outSets = mutableMapOf() init { val forwardsGraph = ControlFlowAnalyzer().createGraph(owner, method) graph = if (backwards) { EdgeReversedGraph(forwardsGraph) } else { forwardsGraph } } protected open fun createEntrySet(): T = createInitialSet() protected abstract fun createInitialSet(): T protected abstract fun join(set1: T, set2: T): T protected abstract fun transfer(set: T, insn: AbstractInsnNode): T public fun getInSet(insn: AbstractInsnNode): T? { return getInSet(method.instructions.indexOf(insn)) } public fun getInSet(index: Int): T? { return inSets[index] } public fun getOutSet(insn: AbstractInsnNode): T? { return getOutSet(method.instructions.indexOf(insn)) } public fun getOutSet(index: Int): T? { return outSets[index] } public fun analyze() { val entrySet = createEntrySet() val initialSet = createInitialSet() val workList = UniqueQueue() workList += graph.vertexSet().filter { vertex -> graph.inDegreeOf(vertex) == 0 } while (true) { val node = workList.removeFirstOrNull() ?: break val predecessors = graph.incomingEdgesOf(node).map { edge -> outSets[graph.getEdgeSource(edge)] ?: initialSet } val inSet = if (predecessors.isEmpty()) { entrySet } else { predecessors.reduce(this::join) } inSets[node] = inSet val outSet = transfer(inSet, method.instructions[node]) if (outSets[node] != outSet) { outSets[node] = outSet for (edge in graph.outgoingEdgesOf(node)) { val successor = graph.getEdgeTarget(edge) workList += successor } } } } }