/* * @(#)InstructionNode.java */ package org.jf.dexlib.Code.Analysis.ssa.graphs; import java.util.Arrays; import org.jf.dexlib.Code.Analysis.AnalyzedInstruction; import org.jf.dexlib.Code.Instruction; import org.jf.dexlib.Code.Opcode; import org.jf.dexlib.Code.SingleRegisterInstruction; import org.jf.dexlib.Code.ThreeRegisterInstruction; import org.jf.dexlib.Code.TwoRegisterInstruction; /** * * @author Patrick Kuhn */ public class InstructionNode extends AbstractNode { private static int INDEX = 0; private final int idx; /** Instruction. */ private final AnalyzedInstruction instr; /** Destination register. */ private String destination; /** Parameters. */ private final String[] parameters; /** Operation. */ private final Opcode op; public InstructionNode(final AnalyzedInstruction instr) { this.instr = instr; this.idx = this.instr.getInstructionIndex(); int[] register; int target; final Instruction i = this.instr.getInstruction(); if (i instanceof ThreeRegisterInstruction) { final ThreeRegisterInstruction tri = (ThreeRegisterInstruction) i; register = new int[3]; register[2] = tri.getRegisterC(); register[1] = tri.getRegisterB(); register[0] = tri.getRegisterA(); } else if (i instanceof TwoRegisterInstruction) { final TwoRegisterInstruction twori = (TwoRegisterInstruction) i; register = new int[2]; register[1] = twori.getRegisterB(); register[0] = twori.getRegisterA(); } else if (i instanceof SingleRegisterInstruction) { final SingleRegisterInstruction sri = (SingleRegisterInstruction) i; register = new int[1]; register[0] = sri.getRegisterA(); } else { register = null; } if (register == null) { this.destination = null; this.parameters = null; } else { byte offset = 0; if (instr.setsRegister()) { target = instr.getDestinationRegister(); if (target < 0 || target != register[0]) { throw new AssertionError("target was <0 or != registerA"); } this.destination = Integer.toString(target); offset = 1; } else { this.destination = null; } this.parameters = new String[register.length - offset]; for (int j = 0; j < parameters.length; ++j) { this.parameters[j] = Integer.toString(register[j + offset]); } } this.op = instr.getInstruction().opcode; } /** * Create an instruction node without having an <tt>AnalyzedInstruction</tt>. * Primarily eases testing. * @param op operation * @param target target register, if there is none, insert <tt>-1</tt> * @param source source register, i.e. parameters of operation */ public InstructionNode(final Opcode op, final int target, final int... source) { this.instr = null; this.idx = INDEX; ++INDEX; this.op = op; if (target > 0) { this.destination = Integer.toString(target); } else { this.destination = null; } if (source != null) { this.parameters = new String[source.length]; for (int i = 0; i < parameters.length; ++i) { this.parameters[i] = Integer.toString(source[i]); } } else { this.parameters = null; } } @Override public AnalyzedInstruction getInstruction() { return instr; } @Override public boolean isInstruction() { return true; } public int hashCode() { // int hash = 7; // hash = 29 * hash + this.idx; // hash = 29 * hash + Objects.hashCode(this.instr); // hash = 29 * hash + Objects.hashCode(this.destination); // hash = 29 * hash + Arrays.deepHashCode(this.parameters); // hash = 29 * hash + (this.op != null ? this.op.hashCode() : 0); // return hash; return idx; } @Override public boolean equals(final Object o) { boolean result = false; if (o instanceof InstructionNode) { final InstructionNode other = (InstructionNode) o; result = instr.equals(other.instr); } return result; } @Override public String toString() { String result; final int index = idx; if (destination != null || parameters != null) { final StringBuilder sb = new StringBuilder("[" + index + "] "); if (destination != null) { sb.append("v"); sb.append(destination); sb.append(" = "); } sb.append(op.name); sb.append("("); boolean flag = false; if (parameters != null) { for (int i = 0; i < parameters.length; ++i) { flag = true; sb.append("v"); sb.append(parameters[i]); sb.append(", "); } } String res; if (flag) { res = sb.substring(0, sb.length() - 2); } else { res = sb.toString(); } result = res + ")"; } else { result = "[" + index + "] " + op.name; } return result; } @Override public void changeVariableName(final int varOriginal, final String varNewName) { final String var = Integer.toString(varOriginal); boolean found = false; for (int i = 0; !found && i < parameters.length; ++i) { if (parameters[i].equals(var)) { found = true; parameters[i] = varNewName; } } } @Override public void changeDefinitionName(final String newName) { if (newName != null) { this.destination = newName; } else { throw new IllegalArgumentException(); } } public String getDestinationRegister() { return destination; } public String[] getSourceRegisters() { if (parameters == null) { return null; } else { return Arrays.copyOf(parameters, parameters.length); } } }