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     * 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     */
015    public 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    }