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 aef99bbb6..62c95cb3d 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformation.java @@ -178,6 +178,24 @@ public class DebugInformation { return null; } + public GeneratedLocation getNearestCallSite(GeneratedLocation location) { + int keyIndex = indexByKey(callSiteMapping, location); + if (keyIndex < 0) { + keyIndex = 0; + } + while (keyIndex < callSiteMapping.values.length) { + int valueIndex = callSiteMapping.values[keyIndex]; + if (valueIndex >= 0) { + MethodReference method = getExactMethod(valueIndex); + if (method != null) { + return new GeneratedLocation(callSiteMapping.lines[keyIndex], callSiteMapping.columns[keyIndex]); + } + } + ++keyIndex; + } + return null; + } + public MethodReference getCallSite(GeneratedLocation location) { int keyIndex = indexByKey(callSiteMapping, location); if (keyIndex < 0) { 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 07db800e1..5df6e2371 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationBuilder.java @@ -117,21 +117,29 @@ public class DebugInformationBuilder implements DebugInformationEmitter { } @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; - Integer exactMethodIndex = exactMethodMap.get(fullIndex); - if (exactMethodIndex == null) { - exactMethodIndex = exactMethods.size(); - exactMethodMap.put(fullIndex, exactMethodIndex); - exactMethods.add(fullIndex); + public DeferredCallSite emitCallSite() { + DeferredCallSite callSite = new DeferredCallSite() { + int index = callSiteMapping.values.size(); + @Override public void setMethod(MethodReference method) { + int methodIndex = methods.index(method.getDescriptor().toString()); + int classIndex = classes.index(method.getClassName()); + long fullIndex = ((long)classIndex << 32) | methodIndex; + Integer exactMethodIndex = exactMethodMap.get(fullIndex); + if (exactMethodIndex == null) { + exactMethodIndex = exactMethods.size(); + exactMethodMap.put(fullIndex, exactMethodIndex); + exactMethods.add(fullIndex); + } + callSiteMapping.values.set(index, exactMethodIndex); } - callSiteMapping.add(locationProvider, exactMethodIndex); - } else { - callSiteMapping.add(locationProvider, -1); - } + }; + callSiteMapping.add(locationProvider, -1); + return callSite; + } + + @Override + public void emitEmptyCallSite() { + callSiteMapping.add(locationProvider, -1); } @Override 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 6ecb2625b..c83358782 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DebugInformationEmitter.java @@ -17,7 +17,6 @@ package org.teavm.debugging; import org.teavm.codegen.LocationProvider; import org.teavm.model.MethodDescriptor; -import org.teavm.model.MethodReference; /** * @@ -34,7 +33,9 @@ public interface DebugInformationEmitter { void emitVariable(String[] sourceNames, String generatedName); - void emitCallSite(MethodReference method); + DeferredCallSite emitCallSite(); + + void emitEmptyCallSite(); void addClass(String className, String parentName); 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 dfd9258ba..7173a29b4 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java @@ -101,7 +101,13 @@ public class Debugger { DebugInformation mainDebugInfo = debugInformationMap.get(frame.originalLocation.getScript()); GeneratedLocation genLoc = new GeneratedLocation(frame.originalLocation.getLine(), frame.originalLocation.getColumn()); - MethodReference callMethod = mainDebugInfo != null ? mainDebugInfo.getCallSite(genLoc) : null; + MethodReference callMethod = null; + if (mainDebugInfo != null) { + GeneratedLocation callSiteLoc = mainDebugInfo.getNearestCallSite(genLoc); + if (callSiteLoc != null) { + callMethod = mainDebugInfo.getCallSite(callSiteLoc); + } + } String script = frame.originalLocation.getScript(); DebugInformation debugInfo = debugInformationMap.get(script); if (debugInfo != null) { diff --git a/teavm-core/src/main/java/org/teavm/debugging/DeferredCallSite.java b/teavm-core/src/main/java/org/teavm/debugging/DeferredCallSite.java new file mode 100644 index 000000000..c6b14dae4 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/debugging/DeferredCallSite.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.debugging; + +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public interface DeferredCallSite { + void setMethod(MethodReference method); +} 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 f290a0697..58b3d601b 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java +++ b/teavm-core/src/main/java/org/teavm/debugging/DummyDebugInformationEmitter.java @@ -42,7 +42,15 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter { } @Override - public void emitCallSite(MethodReference method) { + public DeferredCallSite emitCallSite() { + return new DeferredCallSite() { + @Override public void setMethod(MethodReference method) { + } + }; + } + + @Override + public void emitEmptyCallSite() { } @Override 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 130a6af84..9527a1aa5 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -24,6 +24,7 @@ import org.teavm.codegen.NamingStrategy; import org.teavm.codegen.SourceWriter; import org.teavm.common.ServiceRepository; import org.teavm.debugging.DebugInformationEmitter; +import org.teavm.debugging.DeferredCallSite; import org.teavm.debugging.DummyDebugInformationEmitter; import org.teavm.javascript.ast.*; import org.teavm.javascript.ni.GeneratorContext; @@ -50,7 +51,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 DeferredCallSite lastCallSite; private static class InjectorHolder { public final Injector injector; @@ -594,17 +595,6 @@ 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 { @@ -1296,7 +1286,6 @@ 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()); @@ -1304,9 +1293,16 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext String className = naming.getNameFor(expr.getMethod().getClassName()); String name = naming.getNameFor(expr.getMethod()); String fullName = naming.getFullNameFor(expr.getMethod()); + DeferredCallSite callSite = null; + boolean shouldEraseCallSite = lastCallSite == null; switch (expr.getType()) { case STATIC: + callSite = debugEmitter.emitCallSite(); + if (lastCallSite == null) { + lastCallSite = callSite; + } writer.append(fullName).append("("); + debugEmitter.emitEmptyCallSite(); for (int i = 0; i < expr.getArguments().size(); ++i) { if (i > 0) { writer.append(",").ws(); @@ -1316,7 +1312,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append(')'); break; case SPECIAL: + callSite = debugEmitter.emitCallSite(); + if (lastCallSite == null) { + lastCallSite = callSite; + } writer.append(fullName).append("("); + debugEmitter.emitEmptyCallSite(); expr.getArguments().get(0).acceptVisitor(this); for (int i = 1; i < expr.getArguments().size(); ++i) { writer.append(",").ws(); @@ -1326,7 +1327,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext break; case DYNAMIC: expr.getArguments().get(0).acceptVisitor(this); + callSite = debugEmitter.emitCallSite(); + if (lastCallSite == null) { + lastCallSite = callSite; + } writer.append(".").append(name).append("("); + debugEmitter.emitEmptyCallSite(); for (int i = 1; i < expr.getArguments().size(); ++i) { if (i > 1) { writer.append(",").ws(); @@ -1336,7 +1342,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append(')'); break; case CONSTRUCTOR: + callSite = debugEmitter.emitCallSite(); + if (lastCallSite == null) { + lastCallSite = callSite; + } writer.append(className).append(".").append(name).append("("); + debugEmitter.emitEmptyCallSite(); for (int i = 0; i < expr.getArguments().size(); ++i) { if (i > 0) { writer.append(",").ws(); @@ -1346,8 +1357,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append(')'); break; } + if (lastCallSite != null) { + lastCallSite.setMethod(expr.getMethod()); + lastCallSite = callSite; + } + if (shouldEraseCallSite) { + lastCallSite = null; + } } - popCallSite(); if (expr.getLocation() != null) { popLocation(); }