From 88c47095a61f539c5d969bc2843c85682fe6f3b9 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Wed, 27 Aug 2014 22:49:28 +0400 Subject: [PATCH] Start refactoring of debug information --- .../org/teavm/common/RecordArrayBuilder.java | 13 +- .../teavm/debugging/ClassNameIterator.java | 9 + .../org/teavm/debugging/DebugInformation.java | 285 +++++++----------- .../java/org/teavm/debugging/Debugger.java | 2 +- .../org/teavm/debugging/DebuggerCallSite.java | 13 + .../debugging/DebuggerCallSiteVisitor.java | 11 + .../debugging/DebuggerStaticCallSite.java | 24 ++ .../debugging/DebuggerVirtualCallSite.java | 48 +++ .../org/teavm/debugging/FileNameIterator.java | 44 +++ .../teavm/debugging/LineNumberIterator.java | 39 +++ .../debugging/SourceLocationIterator.java | 96 ++++++ 11 files changed, 408 insertions(+), 176 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/debugging/ClassNameIterator.java create mode 100644 teavm-core/src/main/java/org/teavm/debugging/DebuggerCallSite.java create mode 100644 teavm-core/src/main/java/org/teavm/debugging/DebuggerCallSiteVisitor.java create mode 100644 teavm-core/src/main/java/org/teavm/debugging/DebuggerStaticCallSite.java create mode 100644 teavm-core/src/main/java/org/teavm/debugging/DebuggerVirtualCallSite.java create mode 100644 teavm-core/src/main/java/org/teavm/debugging/FileNameIterator.java create mode 100644 teavm-core/src/main/java/org/teavm/debugging/LineNumberIterator.java create mode 100644 teavm-core/src/main/java/org/teavm/debugging/SourceLocationIterator.java diff --git a/teavm-core/src/main/java/org/teavm/common/RecordArrayBuilder.java b/teavm-core/src/main/java/org/teavm/common/RecordArrayBuilder.java index 6ed08930d..62481da7d 100644 --- a/teavm-core/src/main/java/org/teavm/common/RecordArrayBuilder.java +++ b/teavm-core/src/main/java/org/teavm/common/RecordArrayBuilder.java @@ -76,7 +76,18 @@ public class RecordArrayBuilder { } 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 { diff --git a/teavm-core/src/main/java/org/teavm/debugging/ClassNameIterator.java b/teavm-core/src/main/java/org/teavm/debugging/ClassNameIterator.java new file mode 100644 index 000000000..e1c7ef818 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/ClassNameIterator.java @@ -0,0 +1,9 @@ +package org.teavm.debugging; + +/** + * + * @author Alexey Andreev + */ +public class ClassNameIterator { + +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java index b67512baf..8a2a664e1 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java @@ -40,41 +40,56 @@ public class DebugInformation { Map variableNameMap; long[] exactMethods; Map exactMethodMap; - FileDescription[] fileDescriptions; - Mapping fileMapping; - Mapping classMapping; - Mapping methodMapping; - Mapping lineMapping; - Mapping callSiteMapping; + RecordArray[] fileDescriptions; + RecordArray fileMapping; + RecordArray classMapping; + RecordArray methodMapping; + RecordArray lineMapping; + RecordArray callSiteMapping; MultiMapping[] variableMappings; RecordArray[] lineCallSites; CFG[] controlFlowGraphs; List classesMetadata; - MethodEntrances methodEntrances; + RecordArray methodEntrances; MethodTree methodTree; - public String[] getCoveredSourceFiles() { + public String[] getFilesNames() { 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 getGeneratedLocations(String fileName, int line) { Integer fileIndex = fileNameMap.get(fileName); if (fileIndex == null) { return Collections.emptyList(); } - FileDescription description = fileIndex >= 0 ? fileDescriptions[fileIndex] : null; + RecordArray description = fileIndex >= 0 ? fileDescriptions[fileIndex] : null; if (description == null) { return Collections.emptyList(); } - if (line >= description.generatedLocationStart.length - 1) { + if (line >= description.size()) { return Collections.emptyList(); } - int start = description.generatedLocationStart[line]; - int end = description.generatedLocationStart[line + 1]; - GeneratedLocation[] resultArray = new GeneratedLocation[(end - start) / 2]; + int[] data = description.get(line).getArray(0); + GeneratedLocation[] resultArray = new GeneratedLocation[data.length / 2]; for (int i = 0; i < resultArray.length; ++i) { - int genLine = description.generatedLocationData[start++]; - int genColumn = description.generatedLocationData[start++]; + int genLine = data[i * 2]; + int genColumn = data[i * 2 + 1]; resultArray[i] = new GeneratedLocation(genLine, genColumn); } return Arrays.asList(resultArray); @@ -84,6 +99,10 @@ public class DebugInformation { return getGeneratedLocations(sourceLocation.getFileName(), sourceLocation.getLine()); } + public SourceLocationIterator iterateOverSourceLocations() { + return new SourceLocationIterator(this); + } + public SourceLocation getSourceLocation(int line, int column) { return getSourceLocation(new GeneratedLocation(line, column)); } @@ -91,7 +110,7 @@ public class DebugInformation { public SourceLocation getSourceLocation(GeneratedLocation generatedLocation) { String fileName = componentByKey(fileMapping, fileNames, 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); } @@ -178,34 +197,31 @@ public class DebugInformation { return null; } - public MethodReference getCallSite(GeneratedLocation location) { + public DebuggerCallSite getCallSite(GeneratedLocation location) { int keyIndex = indexByKey(callSiteMapping, location); - if (keyIndex < 0) { - return null; - } - int valueIndex = callSiteMapping.values[keyIndex]; - if (valueIndex < 0) { - return null; - } - return getExactMethod(valueIndex); + return keyIndex >= 0 ? getCallSite(keyIndex) : null; } - 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)); } - public GeneratedLocation[] getCallSiteEntrances(GeneratedLocation location) { - MethodReference method = getCallSite(location); - if (method == null) { - return null; - } - Set 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) { Integer index = getExactMethodIndex(methodRef); 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()); if (fileIndex == null) { - return new MethodReference[0]; + return new DebuggerCallSite[0]; } RecordArray mapping = lineCallSites[fileIndex]; if (location.getLine() >= mapping.size()) { - return new MethodReference[0]; + return new DebuggerCallSite[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) { - int exactMethodId = callSiteMapping.values[callSiteIds[i]]; - methods[i] = getExactMethod(exactMethodId); + callSites[i] = getCallSite(callSiteIds[i]); } - return methods; + return callSites; } - private T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) { + private T componentByKey(RecordArray mapping, T[] values, GeneratedLocation 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; } @@ -299,14 +314,14 @@ public class DebugInformation { return result; } - private int indexByKey(Mapping mapping, GeneratedLocation location) { - int index = Collections.binarySearch(mapping.keyList(), location); + private int indexByKey(RecordArray mapping, GeneratedLocation location) { + int index = Collections.binarySearch(new LocationList(mapping), location); 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); - return index >= 0 ? mapping.values[index] : -1; + return index >= 0 ? mapping.get(index).get(2) : -1; } private int indexByKey(MultiMapping mapping, GeneratedLocation location) { @@ -363,33 +378,41 @@ public class DebugInformation { int currentFile = -1; int currentLine = -1; while (fileIndex < fileMapping.size() && lineIndex < lineMapping.size()) { - GeneratedLocation fileLoc = fileMapping.key(fileIndex); - GeneratedLocation lineLoc = lineMapping.key(lineIndex); + RecordArray.Record fileRec = fileMapping.get(fileIndex); + RecordArray.Record lineRec = lineMapping.get(lineIndex); + GeneratedLocation fileLoc = key(fileRec); + GeneratedLocation lineLoc = key(lineRec); int cmp = fileLoc.compareTo(lineLoc); if (cmp < 0) { - currentFile = fileMapping.values[fileIndex++]; + currentFile = fileRec.get(2); + fileIndex++; } else if (cmp > 0){ - currentLine = lineMapping.values[lineIndex++]; + currentLine = lineRec.get(2); + lineIndex++; } else { - currentFile = fileMapping.values[fileIndex++]; - currentLine = lineMapping.values[lineIndex++]; + currentFile = fileRec.get(2); + currentLine = lineRec.get(2); + fileIndex++; + lineIndex++; } builder.emit(fileLoc.getLine(), fileLoc.getColumn(), currentFile, currentLine); } while (fileIndex < fileMapping.size()) { - builder.emit(fileMapping.lines[fileIndex], fileMapping.columns[fileIndex], - fileMapping.values[fileIndex], currentLine); - ++fileIndex; + RecordArray.Record fileRec = fileMapping.get(fileIndex++); + builder.emit(fileRec.get(0), fileRec.get(1), fileRec.get(2), currentLine); } while (lineIndex < lineMapping.size()) { - builder.emit(lineMapping.lines[lineIndex], lineMapping.columns[lineIndex], currentFile, - lineMapping.values[lineIndex]); - ++lineIndex; + RecordArray.Record lineRec = lineMapping.get(lineIndex++); + builder.emit(lineRec.get(0), lineRec.get(1), currentFile, lineRec.get(2)); } fileDescriptions = builder.build(); } void rebuildEntrances() { + RecordArrayBuilder builder = new RecordArrayBuilder(0, 1); + for (SourceLocationIterator iter = iterateOverSourceLocations(); !iter.isEndReached(); iter.next()) { + iter.getLocation(); + } methodEntrances = new MethodEntrancesBuilder().build(); } @@ -472,10 +495,11 @@ public class DebugInformation { for (int i = 0; i < lineCallSites.length; ++i) { builders[i] = new RecordArrayBuilder(0, 1); } - for (int i = 0; i < callSiteMapping.lines.length; ++i) { - GeneratedLocation loc = callSiteMapping.key(i); - int methodId = callSiteMapping.values[i]; - if (methodId >= 0) { + for (int i = 0; i < callSiteMapping.size(); ++i) { + RecordArray.Record callSiteRec = callSiteMapping.get(i); + GeneratedLocation loc = key(callSiteRec); + int callSiteType = callSiteRec.get(2); + if (callSiteType != DebuggerCallSite.NONE) { int line = valueByKey(lineMapping, loc); int fileId = valueByKey(fileMapping, loc); if (fileId >= 0 && line >= 0) { @@ -606,14 +630,14 @@ public class DebugInformation { } static class FileDescriptionBuilder { - FileDescriptionProto[] files; + RecordArrayBuilder[] files; int lastFileIndex = -1; int lastSourceLine = -1; public FileDescriptionBuilder(int size) { - files = new FileDescriptionProto[size]; + files = new RecordArrayBuilder[size]; 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; lastSourceLine = sourceLine; - FileDescriptionProto proto = files[fileIndex]; - proto.addLocation(sourceLine, line, column); + RecordArrayBuilder proto = files[fileIndex]; + while (proto.size() <= sourceLine) { + proto.add(); + } + RecordArrayBuilder.RecordSubArray array = proto.get(sourceLine).getArray(0); + array.add(line); + array.add(column); } - public FileDescription[] build() { - FileDescription[] descriptions = new FileDescription[files.length]; + public RecordArray[] build() { + RecordArray[] descriptions = new RecordArray[files.length]; for (int i = 0; i < files.length; ++i) { descriptions[i] = files[i].build(); } @@ -639,81 +668,8 @@ public class DebugInformation { } } - static class FileDescriptionProto { - IntegerArray generatedLocationData = new IntegerArray(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 GeneratedLocation key(RecordArray.Record record) { + return new GeneratedLocation(record.get(0), record.get(1)); } static class MultiMapping { @@ -743,22 +699,21 @@ public class DebugInformation { } static class LocationList extends AbstractList { - private int[] lines; - private int[] columns; + private RecordArray recordArray; - public LocationList(int[] lines, int[] columns) { - this.lines = lines; - this.columns = columns; + public LocationList(RecordArray recordArray) { + this.recordArray = recordArray; } @Override 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 public int size() { - return lines.length; + return recordArray.size(); } } @@ -774,24 +729,6 @@ public class DebugInformation { 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 { int[] data; int[] offsets; diff --git a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java index 9fb9f1d57..e3fd78053 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java @@ -291,7 +291,7 @@ public class Debugger { updateBreakpoints(); return; } - for (String sourceFile : debugInfo.getCoveredSourceFiles()) { + for (String sourceFile : debugInfo.getFilesNames()) { ConcurrentMap list = debugInformationFileMap.get(sourceFile); if (list == null) { list = new ConcurrentHashMap<>(); diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebuggerCallSite.java b/teavm-core/src/main/java/org/teavm/debugging/DebuggerCallSite.java new file mode 100644 index 000000000..6c574acbc --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/DebuggerCallSite.java @@ -0,0 +1,13 @@ +package org.teavm.debugging; + +/** + * + * @author Alexey Andreev + */ +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); +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebuggerCallSiteVisitor.java b/teavm-core/src/main/java/org/teavm/debugging/DebuggerCallSiteVisitor.java new file mode 100644 index 000000000..c393a6abb --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/DebuggerCallSiteVisitor.java @@ -0,0 +1,11 @@ +package org.teavm.debugging; + +/** + * + * @author Alexey Andreev + */ +public interface DebuggerCallSiteVisitor { + void visit(DebuggerVirtualCallSite callSite); + + void visit(DebuggerStaticCallSite callSite); +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebuggerStaticCallSite.java b/teavm-core/src/main/java/org/teavm/debugging/DebuggerStaticCallSite.java new file mode 100644 index 000000000..8a0bd5ace --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/DebuggerStaticCallSite.java @@ -0,0 +1,24 @@ +package org.teavm.debugging; + +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +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); + } +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebuggerVirtualCallSite.java b/teavm-core/src/main/java/org/teavm/debugging/DebuggerVirtualCallSite.java new file mode 100644 index 000000000..86e18551e --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/DebuggerVirtualCallSite.java @@ -0,0 +1,48 @@ +package org.teavm.debugging; + +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +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); + } +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/FileNameIterator.java b/teavm-core/src/main/java/org/teavm/debugging/FileNameIterator.java new file mode 100644 index 000000000..0ae22eb20 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/FileNameIterator.java @@ -0,0 +1,44 @@ +package org.teavm.debugging; + +/** + * + * @author Alexey Andreev + */ +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; + } +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/LineNumberIterator.java b/teavm-core/src/main/java/org/teavm/debugging/LineNumberIterator.java new file mode 100644 index 000000000..cf67bba51 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/LineNumberIterator.java @@ -0,0 +1,39 @@ +package org.teavm.debugging; + +/** + * + * @author Alexey Andreev + */ +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; + } +} diff --git a/teavm-core/src/main/java/org/teavm/debugging/SourceLocationIterator.java b/teavm-core/src/main/java/org/teavm/debugging/SourceLocationIterator.java new file mode 100644 index 000000000..24fc604ca --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/SourceLocationIterator.java @@ -0,0 +1,96 @@ +package org.teavm.debugging; + +import org.teavm.common.RecordArray; + +/** + * + * @author Alexey Andreev + */ +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; + } +}