package org.openrs2.deob.bytecode.analysis import org.objectweb.asm.Opcodes import org.objectweb.asm.tree.AbstractInsnNode import org.objectweb.asm.tree.IincInsnNode import org.objectweb.asm.tree.MethodNode import org.objectweb.asm.tree.VarInsnNode import java.util.Collections public class CopyPropagationAnalyzer(owner: String, method: MethodNode) : DataFlowAnalyzer>(owner, method) { private val allAssignments = mutableSetOf() init { for (insn in method.instructions) { if (insn !is VarInsnNode || !STORE_OPCODES.contains(insn.opcode)) { continue } val previous = insn.previous if (previous !is VarInsnNode || !LOAD_OPCODES.contains(previous.opcode)) { continue } allAssignments += CopyAssignment(insn.`var`, previous.`var`) } } override fun createEntrySet(): Set { return Collections.emptySet() } override fun createInitialSet(): Set { return allAssignments } override fun join(set1: Set, set2: Set): Set { return set1 intersect set2 } override fun transfer(set: Set, insn: AbstractInsnNode): Set { return when { insn is VarInsnNode && STORE_OPCODES.contains(insn.opcode) -> { val newSet = set.minusKilledByAssignmentTo(insn.`var`) val previous = insn.previous if (previous is VarInsnNode && LOAD_OPCODES.contains(previous.opcode)) { newSet.plus(CopyAssignment(insn.`var`, previous.`var`)) } else { newSet } } insn is IincInsnNode -> set.minusKilledByAssignmentTo(insn.`var`) else -> set } } private fun Set.minusKilledByAssignmentTo(index: Int): Set { return filterTo(mutableSetOf()) { it.source != index && it.destination != index } } private companion object { private val LOAD_OPCODES = setOf( Opcodes.ILOAD, Opcodes.LSTORE, Opcodes.FLOAD, Opcodes.DLOAD, Opcodes.ALOAD ) private val STORE_OPCODES = setOf( Opcodes.ISTORE, Opcodes.LSTORE, Opcodes.FSTORE, Opcodes.DSTORE, Opcodes.ASTORE ) } }