1 package serp.bytecode; 2 3 import java.io.*; 4 import java.util.*; 5 6 import serp.bytecode.lowlevel.*; 7 import serp.bytecode.visitor.*; 8 9 /*** 10 * An opcode in a method of a class. 11 * 12 * @author Abe White 13 */ 14 public class Instruction extends CodeEntry implements BCEntity, VisitAcceptor { 15 private Code _owner = null; 16 private int _opcode = Constants.NOP; 17 18 Instruction(Code owner) { 19 _owner = owner; 20 } 21 22 Instruction(Code owner, int opcode) { 23 _owner = owner; 24 _opcode = opcode; 25 } 26 27 /*** 28 * Return the code block that owns this instruction. 29 */ 30 public Code getCode() { 31 return _owner; 32 } 33 34 /*** 35 * Return the name of this instruction. 36 */ 37 public String getName() { 38 return Constants.OPCODE_NAMES[_opcode]; 39 } 40 41 /*** 42 * Return the opcode this instruction represents. 43 */ 44 public int getOpcode() { 45 return _opcode; 46 } 47 48 /*** 49 * Set the opcode this instruction represents. For internal use only. 50 * 51 * @return this instruction, for method chaining 52 */ 53 Instruction setOpcode(int opcode) { 54 _opcode = opcode; 55 return this; 56 } 57 58 /*** 59 * Return the index in the method code byte block at which this opcode 60 * starts. Note that this information may be out of date if the code 61 * block has been modified since last read/written. 62 */ 63 public int getByteIndex() { 64 if (_owner != null) 65 return _owner.getByteIndex(this); 66 return 0; 67 } 68 69 /*** 70 * Notification that a change has been made to this instruction that 71 * alters the structure of the code block, invalidating byte indexes. 72 */ 73 void invalidateByteIndexes() { 74 if (_owner != null) 75 _owner.invalidateByteIndexes(); 76 } 77 78 /*** 79 * Return the line number of this instruction, or null if none. This 80 * method is subject to the validity constraints of {@link #getByteIndex}. 81 * 82 * @see LineNumberTable#getLineNumber(Instruction) 83 */ 84 public LineNumber getLineNumber() { 85 LineNumberTable table = _owner.getLineNumberTable(false); 86 if (table == null) 87 return null; 88 return table.getLineNumber(this); 89 } 90 91 /*** 92 * Return the length in bytes of this opcode, including all arguments. 93 * For many opcodes this method relies on an up-to-date byte index. 94 */ 95 int getLength() { 96 return 1; 97 } 98 99 /*** 100 * Return the logical number of stack positions changed by this 101 * instruction. In other words, ignore weirdness with longs and doubles 102 * taking two stack positions. 103 */ 104 public int getLogicalStackChange() { 105 return getStackChange(); 106 } 107 108 /*** 109 * Return the number of stack positions this instruction pushes 110 * or pops during its execution. 111 * 112 * @return 0 if the stack is not affected by this instruction, a 113 * positive number if it pushes onto the stack, and a negative 114 * number if it pops from the stack 115 */ 116 public int getStackChange() { 117 return 0; 118 } 119 120 /*** 121 * Instructions are equal if their opcodes are the same. Subclasses 122 * should override this method to perform a template comparison: 123 * instructions should compare equal to other instructions of the same 124 * type where the data is either the same or the data is unset. 125 */ 126 public boolean equalsInstruction(Instruction other) { 127 if (other == this) 128 return true; 129 return other.getOpcode() == getOpcode(); 130 } 131 132 public Project getProject() { 133 return _owner.getProject(); 134 } 135 136 public ConstantPool getPool() { 137 return _owner.getPool(); 138 } 139 140 public ClassLoader getClassLoader() { 141 return _owner.getClassLoader(); 142 } 143 144 public boolean isValid() { 145 return _owner != null; 146 } 147 148 public void acceptVisit(BCVisitor visit) { 149 } 150 151 void invalidate() { 152 _owner = null; 153 } 154 155 /*** 156 * Copy the given instruction data. 157 */ 158 void read(Instruction orig) { 159 } 160 161 /*** 162 * Read the arguments for this opcode from the given stream. 163 * This method should be overridden by opcodes that take arguments. 164 */ 165 void read(DataInput in) throws IOException { 166 } 167 168 /*** 169 * Write the arguments for this opcode to the given stream. 170 * This method should be overridden by opcodes that take arguments. 171 */ 172 void write(DataOutput out) throws IOException { 173 } 174 }