serp.bytecode.Instruction Maven / Gradle / Ivy
package serp.bytecode;
import java.io.*;
import java.util.*;
import serp.bytecode.lowlevel.*;
import serp.bytecode.visitor.*;
/**
* An opcode in a method of a class.
*
* @author Abe White
*/
public class Instruction extends CodeEntry implements BCEntity, VisitAcceptor {
private Code _owner = null;
private int _opcode = Constants.NOP;
Instruction(Code owner) {
_owner = owner;
}
Instruction(Code owner, int opcode) {
_owner = owner;
_opcode = opcode;
}
/**
* Return the code block that owns this instruction.
*/
public Code getCode() {
return _owner;
}
/**
* Return the name of this instruction.
*/
public String getName() {
return Constants.OPCODE_NAMES[_opcode];
}
/**
* Return the opcode this instruction represents.
*/
public int getOpcode() {
return _opcode;
}
/**
* Set the opcode this instruction represents. For internal use only.
*
* @return this instruction, for method chaining
*/
Instruction setOpcode(int opcode) {
_opcode = opcode;
return this;
}
/**
* Return the index in the method code byte block at which this opcode
* starts. Note that this information may be out of date if the code
* block has been modified since last read/written.
*/
public int getByteIndex() {
if (_owner != null)
return _owner.getByteIndex(this);
return 0;
}
/**
* Notification that a change has been made to this instruction that
* alters the structure of the code block, invalidating byte indexes.
*/
void invalidateByteIndexes() {
if (_owner != null)
_owner.invalidateByteIndexes();
}
/**
* Return the line number of this instruction, or null if none. This
* method is subject to the validity constraints of {@link #getByteIndex}.
*
* @see LineNumberTable#getLineNumber(Instruction)
*/
public LineNumber getLineNumber() {
LineNumberTable table = _owner.getLineNumberTable(false);
if (table == null)
return null;
return table.getLineNumber(this);
}
/**
* Return the length in bytes of this opcode, including all arguments.
* For many opcodes this method relies on an up-to-date byte index.
*/
int getLength() {
return 1;
}
/**
* Return the logical number of stack positions changed by this
* instruction. In other words, ignore weirdness with longs and doubles
* taking two stack positions.
*/
public int getLogicalStackChange() {
return getStackChange();
}
/**
* Return the number of stack positions this instruction pushes
* or pops during its execution.
*
* @return 0 if the stack is not affected by this instruction, a
* positive number if it pushes onto the stack, and a negative
* number if it pops from the stack
*/
public int getStackChange() {
return 0;
}
/**
* Instructions are equal if their opcodes are the same. Subclasses
* should override this method to perform a template comparison:
* instructions should compare equal to other instructions of the same
* type where the data is either the same or the data is unset.
*/
public boolean equalsInstruction(Instruction other) {
if (other == this)
return true;
return other.getOpcode() == getOpcode();
}
public Project getProject() {
return _owner.getProject();
}
public ConstantPool getPool() {
return _owner.getPool();
}
public ClassLoader getClassLoader() {
return _owner.getClassLoader();
}
public boolean isValid() {
return _owner != null;
}
public void acceptVisit(BCVisitor visit) {
}
void invalidate() {
_owner = null;
}
/**
* Copy the given instruction data.
*/
void read(Instruction orig) {
}
/**
* Read the arguments for this opcode from the given stream.
* This method should be overridden by opcodes that take arguments.
*/
void read(DataInput in) throws IOException {
}
/**
* Write the arguments for this opcode to the given stream.
* This method should be overridden by opcodes that take arguments.
*/
void write(DataOutput out) throws IOException {
}
}