001 package sysModel.classFile.code.instructions;
002
003 import sysModel.classFile.code.InstructionList;
004 import sysModel.classFile.code.Opcode;
005
006 import java.util.Hashtable;
007 import java.util.LinkedList;
008 import java.util.NoSuchElementException;
009
010 /**
011 * A table that relates PC values to line numbers.
012 *
013 * @author Mathias Ricken
014 */
015 public class LineNumberTable {
016 /**
017 * Hash table to convert from PC to line numbers.
018 */
019 Hashtable<Integer, Integer> _pcToLineNumber = new Hashtable<Integer, Integer>();
020
021 /**
022 * Hash table to convert from line numbers to PCs.
023 */
024 Hashtable<Integer, Integer> _lineNumberToPC = new Hashtable<Integer, Integer>();
025
026 /**
027 * PC value just after the last instruction.
028 */
029 int _maxPC;
030
031 /**
032 * Line number value just after the last instruction.
033 */
034 int _maxLineNo;
035
036 /**
037 * Put this PC-line number pair into the hash tables.
038 * @param pc PC value
039 * @param lineNo line number
040 */
041 protected void put(int pc, int lineNo) {
042 _pcToLineNumber.put(pc, lineNo);
043 _lineNumberToPC.put(lineNo, pc);
044 }
045
046 /**
047 * Create the line number table from bytecode.
048 *
049 * @param bytecode bytecode
050 */
051 public LineNumberTable(byte[] bytecode) {
052 int pc = 0;
053 int lineNo = 0;
054 while(pc < bytecode.length) {
055 put(pc, lineNo);
056 pc += Opcode.getInstrSize(bytecode, pc);
057 ++lineNo;
058 }
059 if (pc != bytecode.length) {
060 throw new IllegalArgumentException("Invalid bytecode length");
061 }
062 put(bytecode.length,lineNo);
063 }
064
065 /**
066 * Create a line number table from a list of instructions.
067 *
068 * @param instrList list of instructions
069 */
070 public LineNumberTable(LinkedList<AInstruction> instrList) {
071 int pc = 0;
072 int lineNo = 0;
073 for(AInstruction i : instrList) {
074 put(pc, lineNo);
075 pc += i.getBytecodeLength((short)pc);
076 ++lineNo;
077 }
078 put(pc,instrList.size());
079 }
080
081 /**
082 * Create a line number table from a list of instructions.
083 *
084 * @param ilist list of instructions
085 */
086 public LineNumberTable(InstructionList ilist) {
087 int pc = 0;
088 if (0 < ilist.getLength()) {
089 InstructionList copy = new InstructionList(ilist);
090 copy.setIndex(0);
091 int lineNo = 0;
092 do {
093 put(pc, lineNo);
094 pc += copy.getInstr().getBytecodeLength((short)pc);
095 ++lineNo;
096 } while(copy.advanceIndex());
097 }
098 put(pc,ilist.getLength());
099 }
100
101 /**
102 * Get the line number from the PC.
103 *
104 * @param pc program counter
105 *
106 * @return line number
107 */
108 public int getLineNumber(int pc) throws NoSuchElementException {
109 Integer i = _pcToLineNumber.get(pc);
110 if (null == i) {
111 throw new NoSuchElementException("No line number found for PC=" + pc);
112 }
113 return i;
114 }
115
116 /**
117 * Get the PC from the line number.
118 *
119 * @param lineNo line number
120 *
121 * @return program counter
122 */
123 public int getPC(int lineNo) throws NoSuchElementException {
124 Integer i = _lineNumberToPC.get(lineNo);
125 if (null == i) {
126 throw new NoSuchElementException("No PC found for line no=" + lineNo);
127 }
128 return i;
129 }
130 }