diff --git a/teavm-core/src/main/java/org/teavm/common/RecordArray.java b/teavm-core/src/main/java/org/teavm/common/RecordArray.java index 8f3399dc9..5298b3907 100644 --- a/teavm-core/src/main/java/org/teavm/common/RecordArray.java +++ b/teavm-core/src/main/java/org/teavm/common/RecordArray.java @@ -27,21 +27,26 @@ public class RecordArray { private int[] data; private int[] substart; private int[] subdata; + private int size; - RecordArray(int recordSize, int arraysPerRecord, int[] data, int[] substart, int[] subdata) { + RecordArray(int recordSize, int arraysPerRecord, int size, int[] data, int[] substart, int[] subdata) { this.recordSize = recordSize; this.arraysPerRecord = arraysPerRecord; + this.size = size; this.data = data; this.substart = substart; this.subdata = subdata; } public Record get(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index " + index + " is outside of [0; " + size + ")"); + } return new Record(index * recordSize, index * arraysPerRecord); } public int size() { - return data.length / recordSize; + return size; } public int getRecordSize() { 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 4f5125355..6ed08930d 100644 --- a/teavm-core/src/main/java/org/teavm/common/RecordArrayBuilder.java +++ b/teavm-core/src/main/java/org/teavm/common/RecordArrayBuilder.java @@ -22,6 +22,7 @@ package org.teavm.common; public class RecordArrayBuilder { private int recordSize; private int arraysPerRecord; + private int size; private IntegerArray data = new IntegerArray(1); private IntegerArray substart = new IntegerArray(1); private IntegerArray subdata = new IntegerArray(1); @@ -33,6 +34,9 @@ public class RecordArrayBuilder { } public Record get(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("Index " + index + " is outside of [0; " + size + ")"); + } return new Record(index * recordSize, index * arraysPerRecord); } @@ -45,11 +49,12 @@ public class RecordArrayBuilder { for (int i = 0; i < arraysPerRecord; ++i) { substart.add(-1); } + ++size; return new Record(offset, arrayOffset); } public int size() { - return data.size() / recordSize; + return size; } public int getRecordSize() { @@ -71,7 +76,7 @@ public class RecordArrayBuilder { } builtSubstart[i + 1] = builtSubdata.size(); } - return new RecordArray(recordSize, arraysPerRecord, data.getAll(), builtSubstart, builtSubdata.getAll()); + return new RecordArray(recordSize, arraysPerRecord, size, data.getAll(), builtSubstart, builtSubdata.getAll()); } public class Record { 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 e6c3d61e5..b67512baf 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java @@ -18,6 +18,8 @@ package org.teavm.debugging; import java.io.*; import java.util.*; import org.teavm.common.IntegerArray; +import org.teavm.common.RecordArray; +import org.teavm.common.RecordArrayBuilder; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; @@ -45,6 +47,7 @@ public class DebugInformation { Mapping lineMapping; Mapping callSiteMapping; MultiMapping[] variableMappings; + RecordArray[] lineCallSites; CFG[] controlFlowGraphs; List classesMetadata; MethodEntrances methodEntrances; @@ -258,6 +261,24 @@ public class DebugInformation { } } + public MethodReference[] getCallSites(SourceLocation location) { + Integer fileIndex = fileNameMap.get(location.getFileName()); + if (fileIndex == null) { + return new MethodReference[0]; + } + RecordArray mapping = lineCallSites[fileIndex]; + if (location.getLine() >= mapping.size()) { + return new MethodReference[0]; + } + int[] callSiteIds = mapping.get(location.getLine()).getArray(0); + MethodReference[] methods = new MethodReference[callSiteIds.length]; + for (int i = 0; i < callSiteIds.length; ++i) { + int exactMethodId = callSiteMapping.values[callSiteIds[i]]; + methods[i] = getExactMethod(exactMethodId); + } + return methods; + } + private T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) { int keyIndex = indexByKey(mapping, location); int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1; @@ -283,6 +304,11 @@ public class DebugInformation { return index >= 0 ? index : -index - 2; } + private int valueByKey(Mapping mapping, GeneratedLocation location) { + int index = indexByKey(mapping, location); + return index >= 0 ? mapping.values[index] : -1; + } + private int indexByKey(MultiMapping mapping, GeneratedLocation location) { int index = Collections.binarySearch(mapping.keyList(), location); return index >= 0 ? index : -index - 2; @@ -307,6 +333,7 @@ public class DebugInformation { rebuildFileDescriptions(); rebuildEntrances(); rebuildMethodTree(); + rebuildLineCallSites(); } void rebuildMaps() { @@ -439,6 +466,32 @@ public class DebugInformation { return exactMethodMap.get(entry); } + private void rebuildLineCallSites() { + lineCallSites = new RecordArray[fileNames.length]; + RecordArrayBuilder[] builders = new RecordArrayBuilder[fileNames.length]; + 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) { + int line = valueByKey(lineMapping, loc); + int fileId = valueByKey(fileMapping, loc); + if (fileId >= 0 && line >= 0) { + RecordArrayBuilder builder = builders[fileId]; + while (builder.size() <= line) { + builder.add(); + } + builder.get(line).getArray(0).add(i); + } + } + } + for (int i = 0; i < lineCallSites.length; ++i) { + lineCallSites[i] = builders[i].build(); + } + } + class MethodEntrancesBuilder { int[] start; IntegerArray data; 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 0929833a0..9fb9f1d57 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java @@ -98,18 +98,18 @@ public class Debugger { for (CallFrame frame : callStack) { boolean exits; String script = frame.originalLocation.getScript(); - GeneratedLocation genLoc = new GeneratedLocation(frame.originalLocation.getLine(), - frame.originalLocation.getColumn()); DebugInformation debugInfo = debugInformationMap.get(script); - if (frame.getLocation() != null && debugInfo != null) { - exits = false; - MethodReference callMethod = debugInfo.getCallSite(genLoc); + if (frame.getLocation() != null && frame.getLocation().getFileName() != null && + frame.getLocation().getLine() >= 0 && debugInfo != null) { + MethodReference[] callMethods = debugInfo.getCallSites(frame.getLocation()); exits = addFollowing(debugInfo, frame.getLocation(), script, new HashSet(), successors); - if (enterMethod && callMethod != null) { - for (MethodReference potentialMethod : debugInfo.getOverridingMethods(callMethod)) { - for (GeneratedLocation loc : debugInfo.getMethodEntrances(potentialMethod)) { - successors.add(new JavaScriptLocation(script, loc.getLine(), loc.getColumn())); + if (enterMethod) { + for (MethodReference callMethod : callMethods) { + for (MethodReference potentialMethod : debugInfo.getOverridingMethods(callMethod)) { + for (GeneratedLocation loc : debugInfo.getMethodEntrances(potentialMethod)) { + successors.add(new JavaScriptLocation(script, loc.getLine(), loc.getColumn())); + } } } }