001package serp.bytecode;
002
003import java.io.*;
004import java.util.*;
005
006import serp.bytecode.lowlevel.*;
007import serp.bytecode.visitor.*;
008
009/**
010 * A line number corresponds to a sequence of opcodes that map logically
011 * to a line of source code.
012 *
013 * @author Abe White
014 */
015public class LineNumber implements Comparable, InstructionPtr, BCEntity,
016    VisitAcceptor {
017    private int _line = 0;
018    private LineNumberTable _owner = null;
019    InstructionPtrStrategy _target = new InstructionPtrStrategy(this);
020
021    LineNumber(LineNumberTable owner) {
022        _owner = owner;
023    }
024
025    LineNumber(LineNumberTable owner, int startPc) {
026        this(owner);
027        setStartPc(startPc);
028    }
029
030    /**
031     * Line numbers are stored in a {@link LineNumberTable}.
032     */
033    public LineNumberTable getTable() {
034        return _owner;
035    }
036
037    void invalidate() {
038        _owner = null;
039    }
040
041    /**
042     * Return source line number.
043     */
044    public int getLine() {
045        return _line;
046    }
047
048    /**
049     * Set the source line number.
050     */
051    public void setLine(int lineNumber) {
052        _line = lineNumber;
053    }
054
055    /**
056     * Return the instruction marking the beginning of this line.
057     */
058    public Instruction getStart() {
059        return _target.getTargetInstruction();
060    }
061
062    /**
063     * Return the index into the code byte array at which this line starts.
064     */
065    public int getStartPc() {
066        return _target.getByteIndex();
067    }
068
069    /**
070     * Set the index into the code byte array at which this line starts.
071     */
072    public void setStartPc(int startPc) {
073        _target.setByteIndex(startPc);
074    }
075
076    /**
077     * Set the {@link Instruction} marking the beginning this line.
078     * The instruction must already be a part of the method.
079     */
080    public void setStart(Instruction instruction) {
081        _target.setTargetInstruction(instruction);
082    }
083
084    public void updateTargets() {
085        _target.updateTargets();
086    }
087
088    public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
089        _target.replaceTarget(oldTarget, newTarget);
090    }
091
092    public Project getProject() {
093        return _owner.getProject();
094    }
095
096    public ConstantPool getPool() {
097        return _owner.getPool();
098    }
099
100    public ClassLoader getClassLoader() {
101        return _owner.getClassLoader();
102    }
103
104    public boolean isValid() {
105        return _owner != null;
106    }
107
108    public void acceptVisit(BCVisitor visit) {
109        visit.enterLineNumber(this);
110        visit.exitLineNumber(this);
111    }
112
113    public int compareTo(Object other) {
114        if (!(other instanceof LineNumber))
115            return -1;
116
117        LineNumber ln = (LineNumber) other;
118        if (getStartPc() == ln.getStartPc())
119            return 0;
120        if (getStartPc() < ln.getStartPc())
121            return -1;
122        return 1;
123    }
124
125    void read(DataInput in) throws IOException {
126        setStartPc(in.readUnsignedShort());
127        setLine(in.readUnsignedShort());
128    }
129
130    void write(DataOutput out) throws IOException {
131        out.writeShort(getStartPc());
132        out.writeShort(getLine());
133    }
134
135    public Code getCode() {
136        return _owner.getCode();
137    }
138}