001 package sysModel.classFile.code.instructions; 002 003 import sysModel.classFile.code.Opcode; 004 import sysModel.classFile.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 short getBytecodeLength(short 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, short pc, short 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(short 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 WideBranchInstruction wideBranchInstruction = (WideBranchInstruction)o; 108 109 if (_opcode != wideBranchInstruction._opcode) { 110 return false; 111 } 112 return _target == wideBranchInstruction._target; 113 114 } 115 116 /** 117 * Return hash code. 118 * 119 * @return hash code 120 */ 121 public int hashCode() { 122 int result; 123 result = (int)_opcode; 124 result = 29 * result + _target; 125 return result; 126 } 127 128 /** 129 * Return an array of target indices. 130 * 131 * @return array of target indices. 132 */ 133 public short[] getBranchTargets() { 134 return new short[]{ 135 (short)_target 136 }; 137 } 138 139 /** 140 * Set the branch target indices. 141 * 142 * @param branchTargets array of target indices 143 */ 144 public void setBranchTargets(short[] branchTargets) { 145 if (1 != branchTargets.length) { 146 throw new IllegalArgumentException("Wide branch instruction can only have one target"); 147 } 148 _target = branchTargets[0]; 149 } 150 151 152 /** 153 * Return instruction in human-readable form. 154 * 155 * @return string representation 156 */ 157 public String toString() { 158 StringBuffer x = new StringBuffer(); 159 x.append(Opcode.getOpcodeName(_opcode)); 160 x.append(' '); 161 x.append(_target); 162 return x.toString(); 163 } 164 } 165