001 package serp.bytecode;
002
003 import java.io.*;
004 import java.util.*;
005
006 import serp.bytecode.lowlevel.*;
007 import serp.bytecode.visitor.*;
008
009 /**
010 * An opcode in a method of a class.
011 *
012 * @author Abe White
013 */
014 public class Instruction extends CodeEntry implements BCEntity, VisitAcceptor {
015 private Code _owner = null;
016 private int _opcode = Constants.NOP;
017
018 Instruction(Code owner) {
019 _owner = owner;
020 }
021
022 Instruction(Code owner, int opcode) {
023 _owner = owner;
024 _opcode = opcode;
025 }
026
027 /**
028 * Return the code block that owns this instruction.
029 */
030 public Code getCode() {
031 return _owner;
032 }
033
034 /**
035 * Return the name of this instruction.
036 */
037 public String getName() {
038 return Constants.OPCODE_NAMES[_opcode];
039 }
040
041 /**
042 * Return the opcode this instruction represents.
043 */
044 public int getOpcode() {
045 return _opcode;
046 }
047
048 /**
049 * Set the opcode this instruction represents. For internal use only.
050 *
051 * @return this instruction, for method chaining
052 */
053 Instruction setOpcode(int opcode) {
054 _opcode = opcode;
055 return this;
056 }
057
058 /**
059 * Return the index in the method code byte block at which this opcode
060 * starts. Note that this information may be out of date if the code
061 * block has been modified since last read/written.
062 */
063 public int getByteIndex() {
064 if (_owner != null)
065 return _owner.getByteIndex(this);
066 return 0;
067 }
068
069 /**
070 * Notification that a change has been made to this instruction that
071 * alters the structure of the code block, invalidating byte indexes.
072 */
073 void invalidateByteIndexes() {
074 if (_owner != null)
075 _owner.invalidateByteIndexes();
076 }
077
078 /**
079 * Return the line number of this instruction, or null if none. This
080 * method is subject to the validity constraints of {@link #getByteIndex}.
081 *
082 * @see LineNumberTable#getLineNumber(Instruction)
083 */
084 public LineNumber getLineNumber() {
085 LineNumberTable table = _owner.getLineNumberTable(false);
086 if (table == null)
087 return null;
088 return table.getLineNumber(this);
089 }
090
091 /**
092 * Return the length in bytes of this opcode, including all arguments.
093 * For many opcodes this method relies on an up-to-date byte index.
094 */
095 int getLength() {
096 return 1;
097 }
098
099 /**
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 }