001 package sysModel.classFile.code.instructions; 002 003 import sysModel.classFile.code.Opcode; 004 import sysModel.classFile.Types; 005 006 /** 007 * Branch Java instruction. 008 * 009 * @author Mathias Ricken 010 */ 011 public class BranchInstruction 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 BranchInstruction(byte opcode, int target) { 029 switch(opcode) { 030 case Opcode.IFEQ: 031 case Opcode.IFNE: 032 case Opcode.IFLT: 033 case Opcode.IFGE: 034 case Opcode.IFGT: 035 case Opcode.IFLE: 036 case Opcode.IF_ICMPEQ: 037 case Opcode.IF_ICMPNE: 038 case Opcode.IF_ICMPLT: 039 case Opcode.IF_ICMPGE: 040 case Opcode.IF_ICMPGT: 041 case Opcode.IF_ICMPLE: 042 case Opcode.IF_ACMPEQ: 043 case Opcode.IF_ACMPNE: 044 case Opcode.GOTO: 045 case Opcode.JSR: 046 case Opcode.IFNULL: 047 case Opcode.IFNONNULL: 048 break; 049 default: 050 throw new IllegalArgumentException("Invalid branch opcode"); 051 } 052 _opcode = opcode; 053 _target = target; 054 } 055 056 /** 057 * Get the opcode of this instruction. 058 * 059 * @return opcode 060 */ 061 public byte getOpcode() { 062 return _opcode; 063 } 064 065 /** 066 * Get the length bytecode for this instruction, padded for the specified program counter value. 067 * 068 * @param pc PC for padding 069 * 070 * @return bytecode length 071 */ 072 public short getBytecodeLength(short pc) { 073 return 3; 074 } 075 076 /** 077 * Make a new branch instruction from the bytecode stating at pc, padded using paddingPC, and use the line number 078 * table for branches. 079 * 080 * @param bytecode bytecode 081 * @param pc starting index in bytecode 082 * @param paddingPC PC for padding 083 * @param lnt line number table for branches 084 */ 085 public BranchInstruction(byte[] bytecode, short pc, short paddingPC, LineNumberTable lnt) { 086 _opcode = bytecode[pc]; 087 _target = lnt.getLineNumber(pc + Types.shortFromBytes(bytecode, pc + 1)); 088 } 089 090 /** 091 * Get the bytecode for this instruction, padded for the specified program counter value, with branch targets 092 * according to the specified line number table * @param pc PC for padding 093 * 094 * @param lnt line number table for branches 095 * 096 * @return bytecode 097 */ 098 public byte[] getBytecode(short pc, LineNumberTable lnt) { 099 byte[] b = new byte[getBytecodeLength(pc)]; 100 101 b[0] = getOpcode(); 102 Types.bytesFromShort((short)(lnt.getPC(_target) - pc), b, 1); 103 104 return b; 105 } 106 107 /** 108 * Return true of this instruction and the other object are equal. 109 * 110 * @param o other object 111 * 112 * @return true if equal 113 */ 114 public boolean equals(Object o) { 115 if (this == o) { 116 return true; 117 } 118 if (!(o instanceof BranchInstruction)) { 119 return false; 120 } 121 122 BranchInstruction branchInstruction = (BranchInstruction)o; 123 124 if (_opcode != branchInstruction._opcode) { 125 return false; 126 } 127 return _target == branchInstruction._target; 128 } 129 130 /** 131 * Return hash code. 132 * 133 * @return hash code 134 */ 135 public int hashCode() { 136 int result; 137 result = (int)_opcode; 138 result = 29 * result + _target; 139 return result; 140 } 141 142 /** 143 * Return an array of target indices. 144 * 145 * @return array of target indices. 146 */ 147 public short[] getBranchTargets() { 148 return new short[]{(short)_target}; 149 } 150 151 /** 152 * Set the branch target indices. 153 * 154 * @param branchTargets array of target indices 155 */ 156 public void setBranchTargets(short[] branchTargets) { 157 if (1 != branchTargets.length) { 158 throw new IllegalArgumentException("Branch instruction can only have one target"); 159 } 160 _target = branchTargets[0]; 161 } 162 163 /** 164 * Return instruction in human-readable form. 165 * 166 * @return string representation 167 */ 168 public String toString() { 169 StringBuffer x = new StringBuffer(); 170 x.append(Opcode.getOpcodeName(_opcode)); 171 x.append(' '); 172 x.append(_target); 173 return x.toString(); 174 } 175 } 176