Adds reordering of call sites to achieve natural stepping in call

hierarchy.
This commit is contained in:
Alexey Andreev 2014-08-22 23:01:19 +04:00
parent 0f81841cf5
commit 3bc8887e4f
7 changed files with 116 additions and 32 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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);
}

View File

@ -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

View File

@ -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<NodeLocation> locationStack = new ArrayDeque<>();
private Deque<MethodReference> 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();
}