Debug information construction

This commit is contained in:
Alexey Andreev 2014-07-27 15:23:01 +04:00
parent 71415e71e1
commit 3b939d0853
7 changed files with 166 additions and 47 deletions

View File

@ -15,18 +15,26 @@
*/
package org.teavm.debugging;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class CallFrame {
private SourceLocation location;
private MethodReference method;
CallFrame(SourceLocation location) {
CallFrame(SourceLocation location, MethodReference method) {
this.location = location;
this.method = method;
}
public SourceLocation getLocation() {
return location;
}
public MethodReference getMethod() {
return method;
}
}

View File

@ -16,7 +16,6 @@
package org.teavm.debugging;
import java.util.*;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
/**
@ -24,31 +23,31 @@ import org.teavm.model.MethodReference;
* @author Alexey Andreev
*/
public class DebugInformation {
List<String> fileNames = new ArrayList<>();
Map<String, Integer> fileNameMap = new HashMap<>();
List<String> classNames = new ArrayList<>();
Map<String, Integer> classNameMap = new HashMap<>();
List<MethodDescriptor> methods = new ArrayList<>();
Map<MethodDescriptor, Integer> methodMap = new HashMap<>();
List<FileDescription> fileDescriptions = new ArrayList<>();
String[] fileNames;
Map<String, Integer> fileNameMap;
FileDescription[] fileDescriptions;
// TODO: for less memory consumption replace with two arrays + custom binary search
GeneratedLocation[] fileNameKeys;
int[] fileNameValues;
GeneratedLocation[] classKeys;
int[] classValues;
GeneratedLocation[] methodKeys;
int[] methodValues;
GeneratedLocation[] lineNumberKeys;
int[] lineNumberValues;
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int lineNumber) {
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) {
Integer fileIndex = fileNameMap.get(fileName);
if (fileIndex == null) {
return Collections.emptyList();
}
FileDescription description = fileDescriptions.get(lineNumber);
return lineNumber < description.generatedLocations.length ?
Arrays.asList(description.generatedLocations[lineNumber]) :
Collections.<GeneratedLocation>emptyList();
FileDescription description = fileIndex >= 0 ? fileDescriptions[fileIndex] : null;
if (description == null) {
return null;
}
GeneratedLocation[] locations = line < description.generatedLocations.length ?
description.generatedLocations[line] : null;
return locations != null ? Arrays.asList(locations) : Collections.<GeneratedLocation>emptyList();
}
public Collection<GeneratedLocation> getGeneratedLocations(SourceLocation sourceLocation) {
return getGeneratedLocations(sourceLocation.getFileName(), sourceLocation.getLine());
}
public SourceLocation getSourceLocation(int line, int column) {
@ -57,18 +56,35 @@ public class DebugInformation {
public SourceLocation getSourceLocation(GeneratedLocation generatedLocation) {
String fileName = componentByKey(fileNameKeys, fileNameValues, fileNames, generatedLocation);
String className = componentByKey(classKeys, classValues, classNames, generatedLocation);
MethodDescriptor method = componentByKey(methodKeys, methodValues, methods, generatedLocation);
int lineNumberIndex = indexByKey(lineNumberKeys, generatedLocation);
int lineNumber = lineNumberIndex >= 0 ? lineNumberValues[lineNumberIndex] : -1;
return new SourceLocation(fileName, lineNumber, new MethodReference(className, method));
return new SourceLocation(fileName, lineNumber);
}
private <T> T componentByKey(GeneratedLocation[] keys, int[] valueIndexes, List<T> values,
public MethodReference getMethodAt(String fileName, int line) {
if (line < 0) {
return null;
}
Integer fileIndex = fileNameMap.get(fileName);
if (fileIndex == null) {
return null;
}
FileDescription description = fileDescriptions[fileIndex];
if (description == null) {
return null;
}
return line < description.methodMap.length ? description.methodMap[line] : null;
}
public MethodReference getMethodAt(SourceLocation sourceLocation) {
return getMethodAt(sourceLocation.getFileName(), sourceLocation.getLine());
}
private <T> T componentByKey(GeneratedLocation[] keys, int[] valueIndexes, T[] values,
GeneratedLocation location) {
int keyIndex = indexByKey(keys, location);
int valueIndex = keyIndex >= 0 ? valueIndexes[keyIndex] : -1;
return valueIndex >= 0 ? values.get(valueIndex) : null;
return valueIndex >= 0 ? values[valueIndex] : null;
}
private int indexByKey(GeneratedLocation[] keys, GeneratedLocation location) {
@ -76,7 +92,8 @@ public class DebugInformation {
return index >= 0 ? index : -index - 2;
}
class FileDescription {
static class FileDescription {
GeneratedLocation[][] generatedLocations;
MethodReference[] methodMap;
}
}

View File

@ -15,6 +15,7 @@
*/
package org.teavm.debugging;
import java.util.*;
import org.teavm.codegen.LocationProvider;
import org.teavm.model.MethodReference;
@ -24,6 +25,15 @@ import org.teavm.model.MethodReference;
*/
public class DebugInformationBuilder implements DebugInformationEmitter {
private LocationProvider locationProvider;
private DebugInformation debugInformation;
private List<String> fileNames = new ArrayList<>();
private Map<String, Integer> fileNameMap = new HashMap<>();
private List<Entry> fileNameEntries = new ArrayList<>();
private List<Entry> lineNumberEntries = new ArrayList<>();
private MethodReference currentMethod;
private String currentFileName;
private int currentLine;
private List<FileDescriptionProto> fileDescriptions = new ArrayList<>();
public LocationProvider getLocationProvider() {
return locationProvider;
@ -33,18 +43,111 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
this.locationProvider = locationProvider;
}
@Override
public void emitFile(String fileName) {
private GeneratedLocation getGeneratedLocation() {
return new GeneratedLocation(locationProvider.getLine(), locationProvider.getColumn());
}
@Override
public void emitLocation(String fileName, int line) {
Integer fileIndex;
if (fileName != null) {
fileIndex = fileNameMap.get(fileName);
if (fileIndex == null) {
fileIndex = fileNames.size();
fileNames.add(fileName);
fileNameMap.put(fileName, fileIndex);
fileDescriptions.add(new FileDescriptionProto());
}
} else {
fileIndex = -1;
}
if (currentFileName != fileName) {
fileNameEntries.add(new Entry(getGeneratedLocation(), fileIndex));
}
if (currentLine != line) {
lineNumberEntries.add(new Entry(getGeneratedLocation(), line));
}
if (fileName != null && line >= 0 && (currentFileName != fileName || currentLine != line)) {
FileDescriptionProto fileDesc = fileDescriptions.get(fileIndex);
fileDesc.setMethod(line, currentMethod);
fileDesc.addGeneratedLocation(line, getGeneratedLocation());
}
}
@Override
public void emitMethod(MethodReference method) {
currentMethod = method;
}
@Override
public void emitLineNumber(String lineNumber) {
public DebugInformation getDebugInformation() {
if (debugInformation == null) {
debugInformation = new DebugInformation();
debugInformation.fileNames = fileNames.toArray(new String[0]);
debugInformation.fileNameMap = new HashMap<>(fileNameMap);
debugInformation.fileNameKeys = new GeneratedLocation[fileNameEntries.size()];
debugInformation.fileNameValues = new int[fileNameEntries.size()];
int index = 0;
for (Entry entry : fileNameEntries) {
debugInformation.fileNameKeys[index] = entry.key;
debugInformation.fileNameValues[index] = entry.value;
index++;
}
debugInformation.lineNumberKeys = new GeneratedLocation[lineNumberEntries.size()];
debugInformation.lineNumberValues = new int[lineNumberEntries.size()];
index = 0;
for (Entry entry : lineNumberEntries) {
debugInformation.lineNumberKeys[index] = entry.key;
debugInformation.lineNumberValues[index] = entry.value;
index++;
}
debugInformation.fileDescriptions = new DebugInformation.FileDescription[fileDescriptions.size()];
index = 0;
for (FileDescriptionProto fileDescProto : fileDescriptions) {
DebugInformation.FileDescription fileDesc = new DebugInformation.FileDescription();
debugInformation.fileDescriptions[index++] = fileDesc;
fileDesc.methodMap = fileDescProto.methodMap.toArray(new MethodReference[0]);
fileDesc.generatedLocations = new GeneratedLocation[fileDescProto.generatedLocations.size()][];
for (int i = 0; i < fileDescProto.generatedLocations.size(); ++i) {
fileDesc.generatedLocations[i] = fileDescProto.generatedLocations.get(index)
.toArray(new GeneratedLocation[0]);
}
}
}
return debugInformation;
}
static class FileDescriptionProto {
List<List<GeneratedLocation>> generatedLocations = new ArrayList<>();
List<MethodReference> methodMap = new ArrayList<>();
void addGeneratedLocation(int line, GeneratedLocation location) {
if (line >= generatedLocations.size()) {
generatedLocations.addAll(Collections.<List<GeneratedLocation>>nCopies(
line - generatedLocations.size() + 1, null));
}
List<GeneratedLocation> existingLocations = generatedLocations.get(line);
existingLocations.add(location);
}
void setMethod(int line, MethodReference method) {
if (line >= methodMap.size()) {
methodMap.addAll(Collections.<MethodReference>nCopies(line - methodMap.size() + 1, null));
}
methodMap.set(line, method);
}
}
static class Entry {
GeneratedLocation key;
int value;
public Entry(GeneratedLocation key, int value) {
this.key = key;
this.value = value;
}
}
}

View File

@ -22,9 +22,7 @@ import org.teavm.model.MethodReference;
* @author Alexey Andreev
*/
public interface DebugInformationEmitter {
void emitFile(String fileName);
void emitLocation(String fileName, int line);
void emitMethod(MethodReference method);
void emitLineNumber(String lineNumber);
}

View File

@ -16,6 +16,7 @@
package org.teavm.debugging;
import java.util.*;
import org.teavm.model.MethodReference;
/**
*
@ -65,12 +66,14 @@ public class Debugger {
return;
}
// TODO: lookup all locations that are "out of" the current location and create temporary breakpoints
javaScriptDebugger.stepOut();
}
public void stepOver() {
if (!javaScriptDebugger.isSuspended()) {
return;
}
javaScriptDebugger.stepOver();
// TODO: lookup all locations that are "after" the current location and create temporary breakpoints
}
@ -115,9 +118,10 @@ public class Debugger {
boolean wasEmpty = false;
for (JavaScriptCallFrame jsFrame : javaScriptDebugger.getCallStack()) {
SourceLocation loc = debugInformation.getSourceLocation(jsFrame.getLocation());
boolean empty = loc.getFileName() != null || loc.getMethod() != null || loc.getLine() < 0;
boolean empty = loc == null || (loc.getFileName() == null && loc.getLine() < 0);
MethodReference method = !empty ? debugInformation.getMethodAt(loc) : null;
if (!empty || !wasEmpty) {
frames.add(new CallFrame(loc));
frames.add(new CallFrame(loc, method));
}
wasEmpty = empty;
}

View File

@ -24,14 +24,10 @@ import org.teavm.model.MethodReference;
*/
public class DummyDebugInformationEmitter implements DebugInformationEmitter {
@Override
public void emitFile(String fileName) {
public void emitLocation(String fileName, int line) {
}
@Override
public void emitMethod(MethodReference method) {
}
@Override
public void emitLineNumber(String lineNumber) {
}
}

View File

@ -15,7 +15,6 @@
*/
package org.teavm.debugging;
import org.teavm.model.MethodReference;
/**
*
@ -24,12 +23,10 @@ import org.teavm.model.MethodReference;
public class SourceLocation {
private String fileName;
private int line;
private MethodReference method;
public SourceLocation(String fileName, int line, MethodReference method) {
public SourceLocation(String fileName, int line) {
this.fileName = fileName;
this.line = line;
this.method = method;
}
public String getFileName() {
@ -39,8 +36,4 @@ public class SourceLocation {
public int getLine() {
return line;
}
public MethodReference getMethod() {
return method;
}
}