mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-23 23:04:50 -08:00
Debug information construction
This commit is contained in:
parent
71415e71e1
commit
3b939d0853
|
@ -15,18 +15,26 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.debugging;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class CallFrame {
|
public class CallFrame {
|
||||||
private SourceLocation location;
|
private SourceLocation location;
|
||||||
|
private MethodReference method;
|
||||||
|
|
||||||
CallFrame(SourceLocation location) {
|
CallFrame(SourceLocation location, MethodReference method) {
|
||||||
this.location = location;
|
this.location = location;
|
||||||
|
this.method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceLocation getLocation() {
|
public SourceLocation getLocation() {
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MethodReference getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package org.teavm.debugging;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.teavm.model.MethodDescriptor;
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,31 +23,31 @@ import org.teavm.model.MethodReference;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class DebugInformation {
|
public class DebugInformation {
|
||||||
List<String> fileNames = new ArrayList<>();
|
String[] fileNames;
|
||||||
Map<String, Integer> fileNameMap = new HashMap<>();
|
Map<String, Integer> fileNameMap;
|
||||||
List<String> classNames = new ArrayList<>();
|
FileDescription[] fileDescriptions;
|
||||||
Map<String, Integer> classNameMap = new HashMap<>();
|
// TODO: for less memory consumption replace with two arrays + custom binary search
|
||||||
List<MethodDescriptor> methods = new ArrayList<>();
|
|
||||||
Map<MethodDescriptor, Integer> methodMap = new HashMap<>();
|
|
||||||
List<FileDescription> fileDescriptions = new ArrayList<>();
|
|
||||||
GeneratedLocation[] fileNameKeys;
|
GeneratedLocation[] fileNameKeys;
|
||||||
int[] fileNameValues;
|
int[] fileNameValues;
|
||||||
GeneratedLocation[] classKeys;
|
|
||||||
int[] classValues;
|
|
||||||
GeneratedLocation[] methodKeys;
|
|
||||||
int[] methodValues;
|
|
||||||
GeneratedLocation[] lineNumberKeys;
|
GeneratedLocation[] lineNumberKeys;
|
||||||
int[] lineNumberValues;
|
int[] lineNumberValues;
|
||||||
|
|
||||||
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int lineNumber) {
|
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) {
|
||||||
Integer fileIndex = fileNameMap.get(fileName);
|
Integer fileIndex = fileNameMap.get(fileName);
|
||||||
if (fileIndex == null) {
|
if (fileIndex == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
FileDescription description = fileDescriptions.get(lineNumber);
|
FileDescription description = fileIndex >= 0 ? fileDescriptions[fileIndex] : null;
|
||||||
return lineNumber < description.generatedLocations.length ?
|
if (description == null) {
|
||||||
Arrays.asList(description.generatedLocations[lineNumber]) :
|
return null;
|
||||||
Collections.<GeneratedLocation>emptyList();
|
}
|
||||||
|
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) {
|
public SourceLocation getSourceLocation(int line, int column) {
|
||||||
|
@ -57,18 +56,35 @@ public class DebugInformation {
|
||||||
|
|
||||||
public SourceLocation getSourceLocation(GeneratedLocation generatedLocation) {
|
public SourceLocation getSourceLocation(GeneratedLocation generatedLocation) {
|
||||||
String fileName = componentByKey(fileNameKeys, fileNameValues, fileNames, 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 lineNumberIndex = indexByKey(lineNumberKeys, generatedLocation);
|
||||||
int lineNumber = lineNumberIndex >= 0 ? lineNumberValues[lineNumberIndex] : -1;
|
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) {
|
GeneratedLocation location) {
|
||||||
int keyIndex = indexByKey(keys, location);
|
int keyIndex = indexByKey(keys, location);
|
||||||
int valueIndex = keyIndex >= 0 ? valueIndexes[keyIndex] : -1;
|
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) {
|
private int indexByKey(GeneratedLocation[] keys, GeneratedLocation location) {
|
||||||
|
@ -76,7 +92,8 @@ public class DebugInformation {
|
||||||
return index >= 0 ? index : -index - 2;
|
return index >= 0 ? index : -index - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FileDescription {
|
static class FileDescription {
|
||||||
GeneratedLocation[][] generatedLocations;
|
GeneratedLocation[][] generatedLocations;
|
||||||
|
MethodReference[] methodMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.debugging;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
import org.teavm.codegen.LocationProvider;
|
import org.teavm.codegen.LocationProvider;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
@ -24,6 +25,15 @@ import org.teavm.model.MethodReference;
|
||||||
*/
|
*/
|
||||||
public class DebugInformationBuilder implements DebugInformationEmitter {
|
public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
private LocationProvider locationProvider;
|
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() {
|
public LocationProvider getLocationProvider() {
|
||||||
return locationProvider;
|
return locationProvider;
|
||||||
|
@ -33,18 +43,111 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
this.locationProvider = locationProvider;
|
this.locationProvider = locationProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private GeneratedLocation getGeneratedLocation() {
|
||||||
public void emitFile(String fileName) {
|
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
|
@Override
|
||||||
public void emitMethod(MethodReference method) {
|
public void emitMethod(MethodReference method) {
|
||||||
|
currentMethod = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public DebugInformation getDebugInformation() {
|
||||||
public void emitLineNumber(String lineNumber) {
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,7 @@ import org.teavm.model.MethodReference;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public interface DebugInformationEmitter {
|
public interface DebugInformationEmitter {
|
||||||
void emitFile(String fileName);
|
void emitLocation(String fileName, int line);
|
||||||
|
|
||||||
void emitMethod(MethodReference method);
|
void emitMethod(MethodReference method);
|
||||||
|
|
||||||
void emitLineNumber(String lineNumber);
|
|
||||||
}
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.debugging;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -65,12 +66,14 @@ public class Debugger {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: lookup all locations that are "out of" the current location and create temporary breakpoints
|
// TODO: lookup all locations that are "out of" the current location and create temporary breakpoints
|
||||||
|
javaScriptDebugger.stepOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stepOver() {
|
public void stepOver() {
|
||||||
if (!javaScriptDebugger.isSuspended()) {
|
if (!javaScriptDebugger.isSuspended()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
javaScriptDebugger.stepOver();
|
||||||
// TODO: lookup all locations that are "after" the current location and create temporary breakpoints
|
// TODO: lookup all locations that are "after" the current location and create temporary breakpoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,9 +118,10 @@ public class Debugger {
|
||||||
boolean wasEmpty = false;
|
boolean wasEmpty = false;
|
||||||
for (JavaScriptCallFrame jsFrame : javaScriptDebugger.getCallStack()) {
|
for (JavaScriptCallFrame jsFrame : javaScriptDebugger.getCallStack()) {
|
||||||
SourceLocation loc = debugInformation.getSourceLocation(jsFrame.getLocation());
|
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) {
|
if (!empty || !wasEmpty) {
|
||||||
frames.add(new CallFrame(loc));
|
frames.add(new CallFrame(loc, method));
|
||||||
}
|
}
|
||||||
wasEmpty = empty;
|
wasEmpty = empty;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,14 +24,10 @@ import org.teavm.model.MethodReference;
|
||||||
*/
|
*/
|
||||||
public class DummyDebugInformationEmitter implements DebugInformationEmitter {
|
public class DummyDebugInformationEmitter implements DebugInformationEmitter {
|
||||||
@Override
|
@Override
|
||||||
public void emitFile(String fileName) {
|
public void emitLocation(String fileName, int line) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emitMethod(MethodReference method) {
|
public void emitMethod(MethodReference method) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void emitLineNumber(String lineNumber) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.debugging;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
import org.teavm.model.MethodReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -24,12 +23,10 @@ import org.teavm.model.MethodReference;
|
||||||
public class SourceLocation {
|
public class SourceLocation {
|
||||||
private String fileName;
|
private String fileName;
|
||||||
private int line;
|
private int line;
|
||||||
private MethodReference method;
|
|
||||||
|
|
||||||
public SourceLocation(String fileName, int line, MethodReference method) {
|
public SourceLocation(String fileName, int line) {
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
this.line = line;
|
this.line = line;
|
||||||
this.method = method;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFileName() {
|
public String getFileName() {
|
||||||
|
@ -39,8 +36,4 @@ public class SourceLocation {
|
||||||
public int getLine() {
|
public int getLine() {
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodReference getMethod() {
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user