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 aeed36f18..0fc447da9 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java @@ -39,11 +39,14 @@ public class DebugInformation { Map methodMap; String[] variableNames; Map variableNameMap; + long[] exactMethods; + Map exactMethodMap; FileDescription[] fileDescriptions; Mapping fileMapping; Mapping classMapping; Mapping methodMapping; Mapping lineMapping; + Mapping callSiteMapping; MultiMapping[] variableMappings; CFG[] controlFlowGraphs; List classesMetadata; @@ -170,6 +173,25 @@ public class DebugInformation { return null; } + public MethodReference getCallSite(GeneratedLocation location) { + int keyIndex = indexByKey(callSiteMapping, location); + if (keyIndex < 0) { + return null; + } + int valueIndex = callSiteMapping.values[keyIndex]; + if (valueIndex < 0) { + return null; + } + long item = exactMethods[valueIndex]; + int classIndex = (int)(item >> 32); + int methodIndex = (int)item; + return new MethodReference(classNames[classIndex], MethodDescriptor.parse(methods[methodIndex])); + } + + public MethodReference getCallSite(int line, int column) { + return getCallSite(new GeneratedLocation(line, column)); + } + private T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) { int keyIndex = indexByKey(mapping, location); int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1; @@ -216,6 +238,10 @@ public class DebugInformation { fieldMap = mapArray(fields); methodMap = mapArray(methods); variableNameMap = mapArray(variableNames); + exactMethodMap = new HashMap<>(); + for (int i = 0; i < exactMethods.length; ++i) { + exactMethodMap.put(exactMethods[i], i); + } } private Map mapArray(String[] array) { diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java index c69fb4b8f..f1316bc00 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java @@ -19,6 +19,7 @@ import java.util.*; import org.teavm.codegen.LocationProvider; import org.teavm.common.IntegerArray; import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReference; /** * @@ -32,10 +33,13 @@ public class DebugInformationBuilder implements DebugInformationEmitter { private MappedList fields = new MappedList(); private MappedList methods = new MappedList(); private MappedList variableNames = new MappedList(); + private List exactMethods = new ArrayList<>(); + private Map exactMethodMap = new HashMap<>(); private Mapping fileMapping = new Mapping(); private Mapping lineMapping = new Mapping(); private Mapping classMapping = new Mapping(); private Mapping methodMapping = new Mapping(); + private Mapping callSiteMapping = new Mapping(); private Map variableMappings = new HashMap<>(); private MethodDescriptor currentMethod; private String currentClass; @@ -104,6 +108,24 @@ public class DebugInformationBuilder implements DebugInformationEmitter { mapping.add(locationProvider, sourceIndexes); } + @Override + public void emitCallSite(MethodReference method) { + if (method != null) { + int methodIndex = methods.index(method.getDescriptor().toString()); + int classIndex = classes.index(method.getClassName()); + long fullIndex = (((long)classIndex << 32) | methodIndex) + 1; + Integer exactMethodIndex = exactMethodMap.get(fullIndex); + if (exactMethodIndex == null) { + exactMethodIndex = exactMethods.size(); + exactMethodMap.put(fullIndex, exactMethodIndex); + exactMethods.add(fullIndex); + } + callSiteMapping.add(locationProvider, exactMethodIndex); + } else { + callSiteMapping.add(locationProvider, -1); + } + } + @Override public void addClass(String className, String parentName) { int classIndex = classes.index(className); @@ -152,11 +174,17 @@ public class DebugInformationBuilder implements DebugInformationEmitter { debugInformation.fields = fields.getItems(); debugInformation.methods = methods.getItems(); debugInformation.variableNames = variableNames.getItems(); + debugInformation.exactMethods = new long[exactMethods.size()]; + for (int i = 0; i < exactMethods.size(); ++i) { + debugInformation.exactMethods[i] = exactMethods.get(i); + } + debugInformation.exactMethodMap = new HashMap<>(exactMethodMap); debugInformation.fileMapping = fileMapping.build(); debugInformation.lineMapping = lineMapping.build(); debugInformation.classMapping = classMapping.build(); debugInformation.methodMapping = methodMapping.build(); + debugInformation.callSiteMapping = callSiteMapping.build(); debugInformation.variableMappings = new DebugInformation.MultiMapping[variableNames.list.size()]; for (int var : variableMappings.keySet()) { MultiMapping mapping = variableMappings.get(var); diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java index 8789a3153..6ecb2625b 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java @@ -17,6 +17,7 @@ package org.teavm.debugging; import org.teavm.codegen.LocationProvider; import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReference; /** * @@ -33,6 +34,8 @@ public interface DebugInformationEmitter { void emitVariable(String[] sourceNames, String generatedName); + void emitCallSite(MethodReference method); + void addClass(String className, String parentName); void addField(String fieldName, String jsName); diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java index e0d04f96a..4c4dd48cf 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationReader.java @@ -41,10 +41,12 @@ class DebugInformationReader { debugInfo.fields = readStrings(); debugInfo.methods = readStrings(); debugInfo.variableNames = readStrings(); + debugInfo.exactMethods = readExactMethods(); debugInfo.fileMapping = readMapping(); debugInfo.lineMapping = readMapping(); debugInfo.classMapping = readMapping(); debugInfo.methodMapping = readMapping(); + debugInfo.callSiteMapping = readMapping(); debugInfo.variableMappings = readVariableMappings(debugInfo.variableNames.length); debugInfo.classesMetadata = readClassesMetadata(debugInfo.classNames.length); debugInfo.controlFlowGraphs = readCFGs(debugInfo.fileNames.length); @@ -185,6 +187,18 @@ class DebugInformationReader { return array; } + private long[] readExactMethods() throws IOException { + long[] result = new long[readUnsignedNumber()]; + int lastClass = 0; + int lastMethod = 0; + for (int i = 0; i < result.length; ++i) { + lastClass += readNumber(); + lastMethod += readNumber(); + result[i] = ((long)lastClass << 32) | lastMethod; + } + return result; + } + private int[] readRle() throws IOException { int[] array = new int[readUnsignedNumber()]; for (int i = 0; i < array.length;) { diff --git a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java index ab796da2e..40ac27aa7 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationWriter.java @@ -41,11 +41,13 @@ class DebugInformationWriter { writeStringArray(debugInfo.fields); writeStringArray(debugInfo.methods); writeStringArray(debugInfo.variableNames); + writeExactMethods(debugInfo.exactMethods); writeMapping(debugInfo.fileMapping); writeMapping(debugInfo.lineMapping); writeMapping(debugInfo.classMapping); writeMapping(debugInfo.methodMapping); + writeMapping(debugInfo.callSiteMapping); writeVariableMappings(debugInfo); writeClassMetadata(debugInfo.classesMetadata); writeCFGs(debugInfo); @@ -97,6 +99,21 @@ class DebugInformationWriter { } } + private void writeExactMethods(long[] array) throws IOException { + int lastClass = 0; + int lastMethod = 0; + writeUnsignedNumber(array.length); + for (int i = 0; i < array.length; ++i) { + long item = array[i]; + int classIndex = (int)(item >> 32); + int methodIndex = (int)item; + writeNumber(classIndex - lastClass); + lastClass = classIndex; + writeNumber(methodIndex - lastMethod); + lastMethod = methodIndex; + } + } + private void writeMapping(DebugInformation.MultiMapping mapping) throws IOException { int[] lines = mapping.lines.clone(); int last = 0; diff --git a/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java b/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java index 70aeaa412..f290a0697 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java @@ -17,6 +17,7 @@ package org.teavm.debugging; import org.teavm.codegen.LocationProvider; import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReference; /** @@ -40,6 +41,10 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter { public void emitVariable(String[] sourceName, String generatedName) { } + @Override + public void emitCallSite(MethodReference method) { + } + @Override public void setLocationProvider(LocationProvider locationProvider) { } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index eb0291963..130a6af84 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -50,6 +50,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext private ServiceRepository services; private DebugInformationEmitter debugEmitter = new DummyDebugInformationEmitter(); private Deque locationStack = new ArrayDeque<>(); + private Deque callSiteStack = new ArrayDeque<>(); private static class InjectorHolder { public final Injector injector; @@ -593,6 +594,17 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } } + private void pushCallSite(MethodReference method) { + callSiteStack.push(method); + debugEmitter.emitCallSite(method); + } + + private void popCallSite() { + callSiteStack.pop(); + MethodReference method = callSiteStack.peek(); + debugEmitter.emitCallSite(method); + } + @Override public void visit(AssignmentStatement statement) throws RenderingException { try { @@ -1284,6 +1296,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (expr.getLocation() != null) { pushLocation(expr.getLocation()); } + pushCallSite(expr.getMethod()); Injector injector = getInjector(expr.getMethod()); if (injector != null) { injector.generate(new InjectorContextImpl(expr.getArguments()), expr.getMethod()); @@ -1334,6 +1347,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext break; } } + popCallSite(); if (expr.getLocation() != null) { popLocation(); }