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    }