serp.bytecode.LineNumberTable Maven / Gradle / Ivy
package serp.bytecode;
import java.io.*;
import java.util.*;
import serp.bytecode.visitor.*;
/**
* Code blocks compiled from source have line number tables mapping
* opcodes to source lines. This table automatically maintains line
* numbers in ascending order by their start program counter position
* at all times.
*
* @author Abe White
*/
public class LineNumberTable extends Attribute implements InstructionPtr {
private List _lineNumbers = new ArrayList();
LineNumberTable(int nameIndex, Attributes owner) {
super(nameIndex, owner);
}
/**
* Return the line numbers held in this table.
*/
public LineNumber[] getLineNumbers() {
Collections.sort(_lineNumbers);
return (LineNumber[]) _lineNumbers.toArray
(new LineNumber[_lineNumbers.size()]);
}
/**
* Return the line number for the given program counter, or null if none.
*/
public LineNumber getLineNumber(int pc) {
for (int i = _lineNumbers.size() - 1; i >= 0; i--)
if (((LineNumber) _lineNumbers.get(i))._target.getByteIndex() <= pc)
return (LineNumber) _lineNumbers.get(i);
return null;
}
/**
* Return the line number for the given instruction, or null if none.
*/
public LineNumber getLineNumber(Instruction ins) {
if (ins == null)
return null;
return getLineNumber(ins.getByteIndex());
}
/**
* Set the line numbers for the table. This method is useful when
* importing line numbers from another method.
*/
public void setLineNumbers(LineNumber[] lines) {
clear();
if (lines != null)
for (int i = 0; i < lines.length; i++)
addLineNumber(lines[i]);
}
/**
* Import a line number from another method.
*
* @return the newly added line number
*/
public LineNumber addLineNumber(LineNumber ln) {
LineNumber line = addLineNumber();
line.setStartPc(ln.getStartPc());
line.setLine(ln.getLine());
return line;
}
/**
* Add a new line number to this table.
*/
public LineNumber addLineNumber() {
LineNumber ln = new LineNumber(this);
_lineNumbers.add(ln);
return ln;
}
/**
* Add a new line number to this table.
*/
public LineNumber addLineNumber(int startPc, int line) {
LineNumber ln = addLineNumber();
ln.setStartPc(startPc);
ln.setLine(line);
return ln;
}
/**
* Add a new line number to this table.
*/
public LineNumber addLineNumber(Instruction start, int line) {
LineNumber ln = addLineNumber();
ln.setStart(start);
ln.setLine(line);
return ln;
}
/**
* Clear the line numbers.
*/
public void clear() {
for (int i = 0; i < _lineNumbers.size(); i++)
((LineNumber) _lineNumbers.get(i)).invalidate();
_lineNumbers.clear();
}
/**
* Remove the given line.
*
* @return true if the line was removed, false otherwise
*/
public boolean removeLineNumber(LineNumber ln) {
if (ln == null || !_lineNumbers.remove(ln))
return false;
ln.invalidate();
return true;
}
/**
* Remove the line number for the given program counter.
*
* @return true if the line was removed, false otherwise
*/
public boolean removeLineNumber(int pc) {
return removeLineNumber(getLineNumber(pc));
}
/**
* Remove the line number for the given instruction.
*
* @return true if the line was removed, false otherwise
*/
public boolean removeLineNumber(Instruction ins) {
return removeLineNumber(getLineNumber(ins));
}
public void updateTargets() {
for (int i = 0; i < _lineNumbers.size(); i++)
((LineNumber) _lineNumbers.get(i)).updateTargets();
}
public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
for (int i = 0; i < _lineNumbers.size(); i++)
((LineNumber) _lineNumbers.get(i)).replaceTarget(oldTarget,
newTarget);
}
public void acceptVisit(BCVisitor visit) {
visit.enterLineNumberTable(this);
LineNumber[] lines = getLineNumbers();
for (int i = 0; i < lines.length; i++)
lines[i].acceptVisit(visit);
visit.exitLineNumberTable(this);
}
int getLength() {
return 2 + (4 * _lineNumbers.size());
}
void read(Attribute other) {
setLineNumbers(((LineNumberTable) other).getLineNumbers());
}
void read(DataInput in, int length) throws IOException {
clear();
int numLines = in.readUnsignedShort();
LineNumber lineNumber;
for (int i = 0; i < numLines; i++) {
lineNumber = addLineNumber();
lineNumber.read(in);
}
}
void write(DataOutput out, int length) throws IOException {
LineNumber[] lines = getLineNumbers();
out.writeShort(lines.length);
for (int i = 0; i < lines.length; i++)
lines[i].write(out);
}
public Code getCode() {
return (Code) getOwner();
}
}