001package serp.bytecode;
002
003import java.io.*;
004import java.util.*;
005
006import serp.bytecode.lowlevel.*;
007import serp.bytecode.visitor.*;
008
009/**
010 * An opcode in a method of a class.
011 *
012 * @author Abe White
013 */
014public 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}