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