Start refactoring of debug information

This commit is contained in:
konsoletyper 2014-08-27 22:49:28 +04:00
parent 7e1ff76c5d
commit 88c47095a6
11 changed files with 408 additions and 176 deletions

View File

@ -76,7 +76,18 @@ public class RecordArrayBuilder {
} }
builtSubstart[i + 1] = builtSubdata.size(); builtSubstart[i + 1] = builtSubdata.size();
} }
return new RecordArray(recordSize, arraysPerRecord, size, data.getAll(), builtSubstart, builtSubdata.getAll()); int[] builtSubdataArray = builtSubdata.getAll();
for (int i = 1; i < builtSubstart.length; ++i) {
int start = builtSubstart[i - 1];
int end = builtSubstart[i];
int h = (builtSubstart[i] - start) / 2;
for (int j = 0; j < h; ++j) {
int tmp = builtSubdataArray[start + j];
builtSubdataArray[start + j] = builtSubdataArray[end - j - 1];
builtSubdataArray[end - j - 1] = tmp;
}
}
return new RecordArray(recordSize, arraysPerRecord, size, data.getAll(), builtSubstart, builtSubdataArray);
} }
public class Record { public class Record {

View File

@ -0,0 +1,9 @@
package org.teavm.debugging;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClassNameIterator {
}

View File

@ -40,41 +40,56 @@ public class DebugInformation {
Map<String, Integer> variableNameMap; Map<String, Integer> variableNameMap;
long[] exactMethods; long[] exactMethods;
Map<Long, Integer> exactMethodMap; Map<Long, Integer> exactMethodMap;
FileDescription[] fileDescriptions; RecordArray[] fileDescriptions;
Mapping fileMapping; RecordArray fileMapping;
Mapping classMapping; RecordArray classMapping;
Mapping methodMapping; RecordArray methodMapping;
Mapping lineMapping; RecordArray lineMapping;
Mapping callSiteMapping; RecordArray callSiteMapping;
MultiMapping[] variableMappings; MultiMapping[] variableMappings;
RecordArray[] lineCallSites; RecordArray[] lineCallSites;
CFG[] controlFlowGraphs; CFG[] controlFlowGraphs;
List<ClassMetadata> classesMetadata; List<ClassMetadata> classesMetadata;
MethodEntrances methodEntrances; RecordArray methodEntrances;
MethodTree methodTree; MethodTree methodTree;
public String[] getCoveredSourceFiles() { public String[] getFilesNames() {
return fileNames.clone(); return fileNames.clone();
} }
public String[] getVariableNames() {
return variableNames.clone();
}
public LineNumberIterator iterateOverLineNumbers() {
return new LineNumberIterator(this);
}
public FileNameIterator iterateOverFileNames() {
return new FileNameIterator(this);
}
public String getFileName(int fileNameId) {
return fileNames[fileNameId];
}
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) { public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) {
Integer fileIndex = fileNameMap.get(fileName); Integer fileIndex = fileNameMap.get(fileName);
if (fileIndex == null) { if (fileIndex == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
FileDescription description = fileIndex >= 0 ? fileDescriptions[fileIndex] : null; RecordArray description = fileIndex >= 0 ? fileDescriptions[fileIndex] : null;
if (description == null) { if (description == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
if (line >= description.generatedLocationStart.length - 1) { if (line >= description.size()) {
return Collections.emptyList(); return Collections.emptyList();
} }
int start = description.generatedLocationStart[line]; int[] data = description.get(line).getArray(0);
int end = description.generatedLocationStart[line + 1]; GeneratedLocation[] resultArray = new GeneratedLocation[data.length / 2];
GeneratedLocation[] resultArray = new GeneratedLocation[(end - start) / 2];
for (int i = 0; i < resultArray.length; ++i) { for (int i = 0; i < resultArray.length; ++i) {
int genLine = description.generatedLocationData[start++]; int genLine = data[i * 2];
int genColumn = description.generatedLocationData[start++]; int genColumn = data[i * 2 + 1];
resultArray[i] = new GeneratedLocation(genLine, genColumn); resultArray[i] = new GeneratedLocation(genLine, genColumn);
} }
return Arrays.asList(resultArray); return Arrays.asList(resultArray);
@ -84,6 +99,10 @@ public class DebugInformation {
return getGeneratedLocations(sourceLocation.getFileName(), sourceLocation.getLine()); return getGeneratedLocations(sourceLocation.getFileName(), sourceLocation.getLine());
} }
public SourceLocationIterator iterateOverSourceLocations() {
return new SourceLocationIterator(this);
}
public SourceLocation getSourceLocation(int line, int column) { public SourceLocation getSourceLocation(int line, int column) {
return getSourceLocation(new GeneratedLocation(line, column)); return getSourceLocation(new GeneratedLocation(line, column));
} }
@ -91,7 +110,7 @@ public class DebugInformation {
public SourceLocation getSourceLocation(GeneratedLocation generatedLocation) { public SourceLocation getSourceLocation(GeneratedLocation generatedLocation) {
String fileName = componentByKey(fileMapping, fileNames, generatedLocation); String fileName = componentByKey(fileMapping, fileNames, generatedLocation);
int lineNumberIndex = indexByKey(lineMapping, generatedLocation); int lineNumberIndex = indexByKey(lineMapping, generatedLocation);
int lineNumber = lineNumberIndex >= 0 ? lineMapping.values[lineNumberIndex] : -1; int lineNumber = lineNumberIndex >= 0 ? lineMapping.get(lineNumberIndex).get(2) : -1;
return new SourceLocation(fileName, lineNumber); return new SourceLocation(fileName, lineNumber);
} }
@ -178,34 +197,31 @@ public class DebugInformation {
return null; return null;
} }
public MethodReference getCallSite(GeneratedLocation location) { public DebuggerCallSite getCallSite(GeneratedLocation location) {
int keyIndex = indexByKey(callSiteMapping, location); int keyIndex = indexByKey(callSiteMapping, location);
if (keyIndex < 0) { return keyIndex >= 0 ? getCallSite(keyIndex) : null;
return null;
}
int valueIndex = callSiteMapping.values[keyIndex];
if (valueIndex < 0) {
return null;
}
return getExactMethod(valueIndex);
} }
public MethodReference getCallSite(int line, int column) { private DebuggerCallSite getCallSite(int index) {
RecordArray.Record record = callSiteMapping.get(index);
int type = record.get(0);
int[] data = record.getArray(0);
switch (type) {
case DebuggerCallSite.NONE:
return null;
case DebuggerCallSite.STATIC:
return new DebuggerStaticCallSite(getExactMethod(data[0]));
case DebuggerCallSite.VIRTUAL:
return new DebuggerVirtualCallSite(getExactMethod(data[0]), data[1], variableNames[data[1]]);
default:
throw new AssertionError("Unrecognized call site type: " + type);
}
}
public DebuggerCallSite getCallSite(int line, int column) {
return getCallSite(new GeneratedLocation(line, column)); return getCallSite(new GeneratedLocation(line, column));
} }
public GeneratedLocation[] getCallSiteEntrances(GeneratedLocation location) {
MethodReference method = getCallSite(location);
if (method == null) {
return null;
}
Set<GeneratedLocation> locations = new HashSet<>();
for (MethodReference overriding : getOverridingMethods(method)) {
locations.addAll(Arrays.asList(getMethodEntrances(overriding)));
}
return locations.toArray(new GeneratedLocation[0]);
}
public GeneratedLocation[] getMethodEntrances(MethodReference methodRef) { public GeneratedLocation[] getMethodEntrances(MethodReference methodRef) {
Integer index = getExactMethodIndex(methodRef); Integer index = getExactMethodIndex(methodRef);
if (index == null) { if (index == null) {
@ -261,27 +277,26 @@ public class DebugInformation {
} }
} }
public MethodReference[] getCallSites(SourceLocation location) { public DebuggerCallSite[] getCallSites(SourceLocation location) {
Integer fileIndex = fileNameMap.get(location.getFileName()); Integer fileIndex = fileNameMap.get(location.getFileName());
if (fileIndex == null) { if (fileIndex == null) {
return new MethodReference[0]; return new DebuggerCallSite[0];
} }
RecordArray mapping = lineCallSites[fileIndex]; RecordArray mapping = lineCallSites[fileIndex];
if (location.getLine() >= mapping.size()) { if (location.getLine() >= mapping.size()) {
return new MethodReference[0]; return new DebuggerCallSite[0];
} }
int[] callSiteIds = mapping.get(location.getLine()).getArray(0); int[] callSiteIds = mapping.get(location.getLine()).getArray(0);
MethodReference[] methods = new MethodReference[callSiteIds.length]; DebuggerCallSite[] callSites = new DebuggerCallSite[callSiteIds.length];
for (int i = 0; i < callSiteIds.length; ++i) { for (int i = 0; i < callSiteIds.length; ++i) {
int exactMethodId = callSiteMapping.values[callSiteIds[i]]; callSites[i] = getCallSite(callSiteIds[i]);
methods[i] = getExactMethod(exactMethodId);
} }
return methods; return callSites;
} }
private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) { private <T> T componentByKey(RecordArray mapping, T[] values, GeneratedLocation location) {
int keyIndex = indexByKey(mapping, location); int keyIndex = indexByKey(mapping, location);
int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1; int valueIndex = keyIndex >= 0 ? mapping.get(keyIndex).get(2) : -1;
return valueIndex >= 0 ? values[valueIndex] : null; return valueIndex >= 0 ? values[valueIndex] : null;
} }
@ -299,14 +314,14 @@ public class DebugInformation {
return result; return result;
} }
private int indexByKey(Mapping mapping, GeneratedLocation location) { private int indexByKey(RecordArray mapping, GeneratedLocation location) {
int index = Collections.binarySearch(mapping.keyList(), location); int index = Collections.binarySearch(new LocationList(mapping), location);
return index >= 0 ? index : -index - 2; return index >= 0 ? index : -index - 2;
} }
private int valueByKey(Mapping mapping, GeneratedLocation location) { private int valueByKey(RecordArray mapping, GeneratedLocation location) {
int index = indexByKey(mapping, location); int index = indexByKey(mapping, location);
return index >= 0 ? mapping.values[index] : -1; return index >= 0 ? mapping.get(index).get(2) : -1;
} }
private int indexByKey(MultiMapping mapping, GeneratedLocation location) { private int indexByKey(MultiMapping mapping, GeneratedLocation location) {
@ -363,33 +378,41 @@ public class DebugInformation {
int currentFile = -1; int currentFile = -1;
int currentLine = -1; int currentLine = -1;
while (fileIndex < fileMapping.size() && lineIndex < lineMapping.size()) { while (fileIndex < fileMapping.size() && lineIndex < lineMapping.size()) {
GeneratedLocation fileLoc = fileMapping.key(fileIndex); RecordArray.Record fileRec = fileMapping.get(fileIndex);
GeneratedLocation lineLoc = lineMapping.key(lineIndex); RecordArray.Record lineRec = lineMapping.get(lineIndex);
GeneratedLocation fileLoc = key(fileRec);
GeneratedLocation lineLoc = key(lineRec);
int cmp = fileLoc.compareTo(lineLoc); int cmp = fileLoc.compareTo(lineLoc);
if (cmp < 0) { if (cmp < 0) {
currentFile = fileMapping.values[fileIndex++]; currentFile = fileRec.get(2);
fileIndex++;
} else if (cmp > 0){ } else if (cmp > 0){
currentLine = lineMapping.values[lineIndex++]; currentLine = lineRec.get(2);
lineIndex++;
} else { } else {
currentFile = fileMapping.values[fileIndex++]; currentFile = fileRec.get(2);
currentLine = lineMapping.values[lineIndex++]; currentLine = lineRec.get(2);
fileIndex++;
lineIndex++;
} }
builder.emit(fileLoc.getLine(), fileLoc.getColumn(), currentFile, currentLine); builder.emit(fileLoc.getLine(), fileLoc.getColumn(), currentFile, currentLine);
} }
while (fileIndex < fileMapping.size()) { while (fileIndex < fileMapping.size()) {
builder.emit(fileMapping.lines[fileIndex], fileMapping.columns[fileIndex], RecordArray.Record fileRec = fileMapping.get(fileIndex++);
fileMapping.values[fileIndex], currentLine); builder.emit(fileRec.get(0), fileRec.get(1), fileRec.get(2), currentLine);
++fileIndex;
} }
while (lineIndex < lineMapping.size()) { while (lineIndex < lineMapping.size()) {
builder.emit(lineMapping.lines[lineIndex], lineMapping.columns[lineIndex], currentFile, RecordArray.Record lineRec = lineMapping.get(lineIndex++);
lineMapping.values[lineIndex]); builder.emit(lineRec.get(0), lineRec.get(1), currentFile, lineRec.get(2));
++lineIndex;
} }
fileDescriptions = builder.build(); fileDescriptions = builder.build();
} }
void rebuildEntrances() { void rebuildEntrances() {
RecordArrayBuilder builder = new RecordArrayBuilder(0, 1);
for (SourceLocationIterator iter = iterateOverSourceLocations(); !iter.isEndReached(); iter.next()) {
iter.getLocation();
}
methodEntrances = new MethodEntrancesBuilder().build(); methodEntrances = new MethodEntrancesBuilder().build();
} }
@ -472,10 +495,11 @@ public class DebugInformation {
for (int i = 0; i < lineCallSites.length; ++i) { for (int i = 0; i < lineCallSites.length; ++i) {
builders[i] = new RecordArrayBuilder(0, 1); builders[i] = new RecordArrayBuilder(0, 1);
} }
for (int i = 0; i < callSiteMapping.lines.length; ++i) { for (int i = 0; i < callSiteMapping.size(); ++i) {
GeneratedLocation loc = callSiteMapping.key(i); RecordArray.Record callSiteRec = callSiteMapping.get(i);
int methodId = callSiteMapping.values[i]; GeneratedLocation loc = key(callSiteRec);
if (methodId >= 0) { int callSiteType = callSiteRec.get(2);
if (callSiteType != DebuggerCallSite.NONE) {
int line = valueByKey(lineMapping, loc); int line = valueByKey(lineMapping, loc);
int fileId = valueByKey(fileMapping, loc); int fileId = valueByKey(fileMapping, loc);
if (fileId >= 0 && line >= 0) { if (fileId >= 0 && line >= 0) {
@ -606,14 +630,14 @@ public class DebugInformation {
} }
static class FileDescriptionBuilder { static class FileDescriptionBuilder {
FileDescriptionProto[] files; RecordArrayBuilder[] files;
int lastFileIndex = -1; int lastFileIndex = -1;
int lastSourceLine = -1; int lastSourceLine = -1;
public FileDescriptionBuilder(int size) { public FileDescriptionBuilder(int size) {
files = new FileDescriptionProto[size]; files = new RecordArrayBuilder[size];
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
files[i] = new FileDescriptionProto(); files[i] = new RecordArrayBuilder(0, 1);
} }
} }
@ -626,12 +650,17 @@ public class DebugInformation {
} }
lastFileIndex = fileIndex; lastFileIndex = fileIndex;
lastSourceLine = sourceLine; lastSourceLine = sourceLine;
FileDescriptionProto proto = files[fileIndex]; RecordArrayBuilder proto = files[fileIndex];
proto.addLocation(sourceLine, line, column); while (proto.size() <= sourceLine) {
proto.add();
}
RecordArrayBuilder.RecordSubArray array = proto.get(sourceLine).getArray(0);
array.add(line);
array.add(column);
} }
public FileDescription[] build() { public RecordArray[] build() {
FileDescription[] descriptions = new FileDescription[files.length]; RecordArray[] descriptions = new RecordArray[files.length];
for (int i = 0; i < files.length; ++i) { for (int i = 0; i < files.length; ++i) {
descriptions[i] = files[i].build(); descriptions[i] = files[i].build();
} }
@ -639,81 +668,8 @@ public class DebugInformation {
} }
} }
static class FileDescriptionProto { static GeneratedLocation key(RecordArray.Record record) {
IntegerArray generatedLocationData = new IntegerArray(1); return new GeneratedLocation(record.get(0), record.get(1));
IntegerArray generatedLocationPointers = new IntegerArray(1);
IntegerArray generatedLocationStart = new IntegerArray(1);
IntegerArray generatedLocationSize = new IntegerArray(1);
public void addLocation(int sourceLine, int line, int column) {
ensureLine(sourceLine);
generatedLocationSize.set(sourceLine, generatedLocationSize.get(sourceLine) + 1);
int slot = generatedLocationStart.get(sourceLine);
slot = addData(slot, line);
slot = addData(slot, column);
generatedLocationStart.set(sourceLine, slot);
}
int addData(int slot, int value) {
int result = generatedLocationData.size();
generatedLocationData.add(value);
generatedLocationPointers.add(slot);
return result;
}
void ensureLine(int sourceLine) {
while (sourceLine >= generatedLocationSize.size()) {
generatedLocationSize.add(0);
generatedLocationStart.add(-1);
}
}
FileDescription build() {
FileDescription description = new FileDescription();
description.generatedLocationData = new int[generatedLocationData.size()];
description.generatedLocationStart = new int[generatedLocationStart.size() + 1];
int current = 0;
for (int i = 0; i < generatedLocationStart.size(); ++i) {
current += generatedLocationSize.get(i) * 2;
int j = current;
int ptr = generatedLocationStart.get(i);
while (ptr >= 0) {
description.generatedLocationData[--j] = generatedLocationData.get(ptr);
ptr = generatedLocationPointers.get(ptr);
}
description.generatedLocationStart[i + 1] = current;
}
return description;
}
}
static class FileDescription {
int[] generatedLocationData;
int[] generatedLocationStart;
}
static class Mapping {
int[] lines;
int[] columns;
int[] values;
public Mapping(int[] lines, int[] columns, int[] values) {
this.lines = lines;
this.columns = columns;
this.values = values;
}
public LocationList keyList() {
return new LocationList(lines, columns);
}
public int size() {
return lines.length;
}
public GeneratedLocation key(int index) {
return new GeneratedLocation(lines[index], columns[index]);
}
} }
static class MultiMapping { static class MultiMapping {
@ -743,22 +699,21 @@ public class DebugInformation {
} }
static class LocationList extends AbstractList<GeneratedLocation> { static class LocationList extends AbstractList<GeneratedLocation> {
private int[] lines; private RecordArray recordArray;
private int[] columns;
public LocationList(int[] lines, int[] columns) { public LocationList(RecordArray recordArray) {
this.lines = lines; this.recordArray = recordArray;
this.columns = columns;
} }
@Override @Override
public GeneratedLocation get(int index) { public GeneratedLocation get(int index) {
return new GeneratedLocation(lines[index], columns[index]); RecordArray.Record record = recordArray.get(index);
return new GeneratedLocation(record.get(0), record.get(1));
} }
@Override @Override
public int size() { public int size() {
return lines.length; return recordArray.size();
} }
} }
@ -774,24 +729,6 @@ public class DebugInformation {
int[] offsets; int[] offsets;
} }
static class MethodEntrances {
int[] data;
int[] offsets;
public GeneratedLocation[] getEntrances(int index) {
if (index < 0 || index > offsets.length - 1) {
return new GeneratedLocation[0];
}
int start = offsets[index];
int end = offsets[index + 1];
GeneratedLocation[] result = new GeneratedLocation[(end - start) / 2];
for (int i = 0; i < result.length; ++i) {
result[i] = new GeneratedLocation(data[start + i * 2], data[start + i * 2 + 1]);
}
return result;
}
}
class MethodTree { class MethodTree {
int[] data; int[] data;
int[] offsets; int[] offsets;

View File

@ -291,7 +291,7 @@ public class Debugger {
updateBreakpoints(); updateBreakpoints();
return; return;
} }
for (String sourceFile : debugInfo.getCoveredSourceFiles()) { for (String sourceFile : debugInfo.getFilesNames()) {
ConcurrentMap<DebugInformation, Object> list = debugInformationFileMap.get(sourceFile); ConcurrentMap<DebugInformation, Object> list = debugInformationFileMap.get(sourceFile);
if (list == null) { if (list == null) {
list = new ConcurrentHashMap<>(); list = new ConcurrentHashMap<>();

View File

@ -0,0 +1,13 @@
package org.teavm.debugging;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public abstract class DebuggerCallSite {
static final int NONE = 0;
static final int STATIC = 1;
static final int VIRTUAL = 2;
public abstract void acceptVisitor(DebuggerCallSiteVisitor visitor);
}

View File

@ -0,0 +1,11 @@
package org.teavm.debugging;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface DebuggerCallSiteVisitor {
void visit(DebuggerVirtualCallSite callSite);
void visit(DebuggerStaticCallSite callSite);
}

View File

@ -0,0 +1,24 @@
package org.teavm.debugging;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class DebuggerStaticCallSite extends DebuggerCallSite {
private MethodReference method;
DebuggerStaticCallSite(MethodReference method) {
this.method = method;
}
public MethodReference getMethod() {
return method;
}
@Override
public void acceptVisitor(DebuggerCallSiteVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,48 @@
package org.teavm.debugging;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class DebuggerVirtualCallSite extends DebuggerCallSite {
private MethodReference method;
private int variableId;
private String variableName;
DebuggerVirtualCallSite(MethodReference method, int variableId, String variableName) {
this.method = method;
this.variableId = variableId;
this.variableName = variableName;
}
public MethodReference getMethod() {
return method;
}
public void setMethod(MethodReference method) {
this.method = method;
}
public int getVariableId() {
return variableId;
}
public void setVariableId(int variableId) {
this.variableId = variableId;
}
public String getVariableName() {
return variableName;
}
public void setVariableName(String variableName) {
this.variableName = variableName;
}
@Override
public void acceptVisitor(DebuggerCallSiteVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,44 @@
package org.teavm.debugging;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class FileNameIterator {
private DebugInformation debugInformation;
private int index;
FileNameIterator(DebugInformation debugInformation) {
this.debugInformation = debugInformation;
}
public boolean isEndReached() {
return index < debugInformation.fileMapping.size();
}
public GeneratedLocation getLocation() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
return DebugInformation.key(debugInformation.fileMapping.get(index));
}
public int getFileNameId() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
return debugInformation.fileMapping.get(index).get(2);
}
public String getFileName() {
int fileNameId = getFileNameId();
return fileNameId >= 0 ? debugInformation.getFileName(fileNameId) : null;
}
public void next() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
++index;
}
}

View File

@ -0,0 +1,39 @@
package org.teavm.debugging;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class LineNumberIterator {
private DebugInformation debugInformation;
private int index;
LineNumberIterator(DebugInformation debugInformation) {
this.debugInformation = debugInformation;
}
public boolean isEndReached() {
return index < debugInformation.lineMapping.size();
}
public GeneratedLocation getLocation() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
return DebugInformation.key(debugInformation.lineMapping.get(index));
}
public int getLineNumber() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
return debugInformation.lineMapping.get(index).get(2);
}
public void next() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
++index;
}
}

View File

@ -0,0 +1,96 @@
package org.teavm.debugging;
import org.teavm.common.RecordArray;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class SourceLocationIterator {
private DebugInformation debugInformation;
private int lineIndex;
private int fileIndex;
private GeneratedLocation location;
private int fileId = -1;
private int line = -1;
private boolean endReached;
SourceLocationIterator(DebugInformation debugInformation) {
this.debugInformation = debugInformation;
read();
}
public boolean isEndReached() {
return endReached;
}
private void read() {
if (lineIndex >= debugInformation.lineMapping.size()) {
nextFileRecord();
} else if (fileIndex >= debugInformation.fileMapping.size()) {
nextLineRecord();
} else if (fileIndex < debugInformation.fileMapping.size() &&
lineIndex < debugInformation.lineMapping.size()) {
RecordArray.Record fileRecord = debugInformation.fileMapping.get(fileIndex++);
RecordArray.Record lineRecord = debugInformation.lineMapping.get(lineIndex++);
GeneratedLocation fileLoc = DebugInformation.key(fileRecord);
GeneratedLocation lineLoc = DebugInformation.key(lineRecord);
int cmp = fileLoc.compareTo(lineLoc);
if (cmp < 0) {
nextFileRecord();
} else if (cmp > 0) {
nextLineRecord();
} else {
nextFileRecord();
nextLineRecord();
}
} else {
endReached = true;
}
}
private void nextFileRecord() {
RecordArray.Record record = debugInformation.fileMapping.get(fileIndex++);
location = DebugInformation.key(record);
fileId = record.get(2);
}
private void nextLineRecord() {
RecordArray.Record record = debugInformation.lineMapping.get(lineIndex++);
location = DebugInformation.key(record);
line = record.get(2);
}
public void next() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
read();
}
public GeneratedLocation getLocation() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
return location;
}
public int getFileNameId() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
return fileId;
}
public String getFileName() {
int fileId = getFileNameId();
return fileId >= 0 ? debugInformation.getFileName(fileId) : null;
}
public int getLine() {
if (isEndReached()) {
throw new IllegalStateException("End already reached");
}
return line;
}
}