001 package edu.rice.cs.cunit.classFile.code.instructions; 002 003 import edu.rice.cs.cunit.classFile.code.Opcode; 004 005 import java.util.Arrays; 006 007 /** 008 * Generic Java instruction. 009 * 010 * @author Mathias Ricken 011 */ 012 public class GenericInstruction extends AInstruction { 013 /** 014 * Bytecode. 015 */ 016 protected byte[] _code; 017 018 /** 019 * Constructor. 020 * 021 * @param code bytecode for generic instruction 022 */ 023 public GenericInstruction(byte... code) { 024 switch(code[0]) { 025 case Opcode.TABLESWITCH: 026 case Opcode.LOOKUPSWITCH: 027 case Opcode.IFEQ: 028 case Opcode.IFNE: 029 case Opcode.IFLT: 030 case Opcode.IFGE: 031 case Opcode.IFGT: 032 case Opcode.IFLE: 033 case Opcode.IF_ICMPEQ: 034 case Opcode.IF_ICMPNE: 035 case Opcode.IF_ICMPLT: 036 case Opcode.IF_ICMPGE: 037 case Opcode.IF_ICMPGT: 038 case Opcode.IF_ICMPLE: 039 case Opcode.IF_ACMPEQ: 040 case Opcode.IF_ACMPNE: 041 case Opcode.GOTO: 042 case Opcode.JSR: 043 case Opcode.IFNULL: 044 case Opcode.IFNONNULL: 045 case Opcode.GOTO_W: 046 case Opcode.JSR_W: 047 case Opcode.WIDE: 048 throw new IllegalArgumentException("Invalid generic opcode"); 049 } 050 _code = code; 051 } 052 053 /** 054 * Get the opcode of this instruction. 055 * 056 * @return opcode 057 */ 058 public byte getOpcode() { 059 return _code[0]; 060 } 061 062 /** 063 * Get the length bytecode for this instruction, padded for the specified program counter value. 064 * 065 * @param pc PC for padding 066 * 067 * @return bytecode length 068 */ 069 public int getBytecodeLength(int pc) { 070 return Opcode.getInstrSize(_code, 0, 0); 071 } 072 073 /** 074 * Make a new generic instruction from the bytecode stating at pc, padded using paddingPC, and use the line number 075 * table for branches. 076 * 077 * @param bytecode bytecode 078 * @param pc starting index in bytecode 079 * @param paddingPC PC for padding 080 * @param lnt line number table for branches 081 */ 082 public GenericInstruction(byte[] bytecode, int pc, int paddingPC, LineNumberTable lnt) { 083 _code = new byte[Opcode.getInstrSize(bytecode, pc, paddingPC)]; 084 System.arraycopy(bytecode, pc, _code, 0, _code.length); 085 } 086 087 /** 088 * Get the bytecode for this instruction, padded for the specified program counter value, with branch targets 089 * according to the specified line number table 090 * 091 * @param pc PC for padding 092 * @param lnt line number table for branches 093 * 094 * @return bytecode 095 */ 096 public byte[] getBytecode(int pc, LineNumberTable lnt) { 097 return getBytecode(); 098 } 099 100 /** 101 * Get the bytecode for this instruction. 102 * 103 * @return bytecode 104 */ 105 public byte[] getBytecode() { 106 byte[] b = new byte[_code.length]; 107 System.arraycopy(_code, 0, b, 0, _code.length); 108 return b; 109 } 110 111 /** 112 * Return true of this instruction and the other object are equal. 113 * 114 * @param o other object 115 * 116 * @return true if equal 117 */ 118 public boolean equals(Object o) { 119 if (this == o) { 120 return true; 121 } 122 if (!(o instanceof GenericInstruction)) { 123 return false; 124 } 125 126 final GenericInstruction genericInstruction = (GenericInstruction)o; 127 128 if (!Arrays.equals(_code, genericInstruction._code)) { 129 return false; 130 } 131 132 return true; 133 } 134 135 /** 136 * Return hash code. 137 * 138 * @return hash code 139 */ 140 public int hashCode() { 141 return _code[0]; 142 } 143 144 /** 145 * Return an array of target indices. 146 * 147 * @return array of target indices. 148 */ 149 public int[] getBranchTargets() { 150 return new int[0]; 151 } 152 153 /** 154 * Set the branch target indices. 155 * 156 * @param branchTargets array of target indices 157 */ 158 public void setBranchTargets(int[] branchTargets) { 159 if (branchTargets.length != 0) { 160 throw new IllegalArgumentException("Generic instruction cannot have a target"); 161 } 162 } 163 164 /** 165 * Return instruction in human-readable form. 166 * 167 * @return string representation 168 */ 169 public String toString() { 170 StringBuilder x = new StringBuilder(); 171 x.append(Opcode.getOpcodeName(_code[0])); 172 x.append(" "); 173 for(int i = 1; i < _code.length; ++i) { 174 x.append(String.format("%02x", new Object[]{new Byte(_code[i])}) + " "); 175 } 176 return x.toString(); 177 } 178 } 179