mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Implements step into and fixes bugs
This commit is contained in:
parent
2c8902e94a
commit
0c708868a5
|
@ -40,6 +40,10 @@ public class IntegerArray {
|
|||
return array;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
sz = 0;
|
||||
}
|
||||
|
||||
public void optimize() {
|
||||
if (sz > data.length) {
|
||||
data = Arrays.copyOf(data, sz);
|
||||
|
|
|
@ -24,11 +24,14 @@ import org.teavm.model.MethodReference;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
public class CallFrame {
|
||||
JavaScriptLocation originalLocation;
|
||||
private SourceLocation location;
|
||||
private MethodReference method;
|
||||
private Map<String, Variable> variables;
|
||||
|
||||
CallFrame(SourceLocation location, MethodReference method, Map<String, Variable> variables) {
|
||||
CallFrame(JavaScriptLocation originalLocation, SourceLocation location, MethodReference method,
|
||||
Map<String, Variable> variables) {
|
||||
this.originalLocation = originalLocation;
|
||||
this.location = location;
|
||||
this.method = method;
|
||||
this.variables = Collections.unmodifiableMap(variables);
|
||||
|
|
|
@ -136,6 +136,9 @@ public class DebugInformation {
|
|||
if (cfg == null) {
|
||||
return null;
|
||||
}
|
||||
if (location.getLine() >= cfg.offsets.length - 1) {
|
||||
return null;
|
||||
}
|
||||
int start = cfg.offsets[location.getLine()];
|
||||
int end = cfg.offsets[location.getLine() + 1];
|
||||
if (end - start == 1 && cfg.offsets[start] == -1) {
|
||||
|
@ -184,33 +187,80 @@ public class DebugInformation {
|
|||
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]));
|
||||
return getExactMethod(valueIndex);
|
||||
}
|
||||
|
||||
public MethodReference getCallSite(int line, int column) {
|
||||
return getCallSite(new GeneratedLocation(line, column));
|
||||
}
|
||||
|
||||
public GeneratedLocation[] getCallSiteEntrances(GeneratedLocation location) {
|
||||
MethodReference method = getCallSite(location);
|
||||
if (method == null) {
|
||||
return null;
|
||||
}
|
||||
Set<GeneratedLocation> locations = new HashSet<>();
|
||||
for (MethodReference overriding : getOverridingMethods(method)) {
|
||||
locations.addAll(Arrays.asList(getMethodEntrances(overriding)));
|
||||
}
|
||||
return locations.toArray(new GeneratedLocation[0]);
|
||||
}
|
||||
|
||||
public GeneratedLocation[] getMethodEntrances(MethodReference methodRef) {
|
||||
Integer classIndex = classNameMap.get(methodRef.getClassName());
|
||||
if (classIndex == null) {
|
||||
return new GeneratedLocation[0];
|
||||
}
|
||||
Integer methodIndex = methodMap.get(methodRef.getDescriptor().toString());
|
||||
if (methodIndex == null) {
|
||||
return new GeneratedLocation[0];
|
||||
}
|
||||
long exact = ((long)classIndex << 32) | methodIndex;
|
||||
Integer index = exactMethodMap.get(exact);
|
||||
Integer index = getExactMethodIndex(methodRef);
|
||||
if (index == null) {
|
||||
return new GeneratedLocation[0];
|
||||
}
|
||||
return methodEntrances.getEntrances(index);
|
||||
}
|
||||
|
||||
private Integer getExactMethodIndex(MethodReference methodRef) {
|
||||
Integer classIndex = classNameMap.get(methodRef.getClassName());
|
||||
if (classIndex == null) {
|
||||
return null;
|
||||
}
|
||||
Integer methodIndex = methodMap.get(methodRef.getDescriptor().toString());
|
||||
if (methodIndex == null) {
|
||||
return null;
|
||||
}
|
||||
return getExactMethodIndex(classIndex, methodIndex);
|
||||
}
|
||||
|
||||
public MethodReference getExactMethod(int index) {
|
||||
long item = exactMethods[index];
|
||||
int classIndex = (int)(item >> 32);
|
||||
int methodIndex = (int)item;
|
||||
return new MethodReference(classNames[classIndex], MethodDescriptor.parse(methods[methodIndex]));
|
||||
}
|
||||
|
||||
public MethodReference[] getDirectOverridingMethods(MethodReference methodRef) {
|
||||
Integer methodIndex = getExactMethodIndex(methodRef);
|
||||
if (methodIndex == null) {
|
||||
return new MethodReference[0];
|
||||
}
|
||||
int start = methodTree.offsets[methodIndex];
|
||||
int end = methodTree.offsets[methodIndex + 1];
|
||||
MethodReference[] result = new MethodReference[end - start];
|
||||
for (int i = 0; i < result.length; ++i) {
|
||||
result[i] = getExactMethod(methodTree.data[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public MethodReference[] getOverridingMethods(MethodReference methodRef) {
|
||||
Set<MethodReference> overridingMethods = new HashSet<>();
|
||||
getOverridingMethods(methodRef, overridingMethods);
|
||||
return overridingMethods.toArray(new MethodReference[0]);
|
||||
}
|
||||
|
||||
private void getOverridingMethods(MethodReference methodRef, Set<MethodReference> overridingMethods) {
|
||||
if (overridingMethods.add(methodRef)) {
|
||||
for (MethodReference overridingMethod : getDirectOverridingMethods(methodRef)) {
|
||||
getOverridingMethods(overridingMethod, overridingMethods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) {
|
||||
int keyIndex = indexByKey(mapping, location);
|
||||
int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1;
|
||||
|
@ -255,6 +305,7 @@ public class DebugInformation {
|
|||
rebuildMaps();
|
||||
rebuildFileDescriptions();
|
||||
rebuildEntrances();
|
||||
rebuildMethodTree();
|
||||
}
|
||||
|
||||
void rebuildMaps() {
|
||||
|
@ -315,10 +366,76 @@ public class DebugInformation {
|
|||
}
|
||||
|
||||
void rebuildMethodTree() {
|
||||
long[] exactMethods = this.exactMethods.clone();
|
||||
Arrays.sort(exactMethods);
|
||||
IntegerArray methods = new IntegerArray(1);
|
||||
int lastClass = -1;
|
||||
for (int i = 0; i < exactMethods.length; ++i) {
|
||||
long exactMethod = exactMethods[i];
|
||||
int classIndex = (int)(exactMethod >> 32);
|
||||
if (classIndex != lastClass) {
|
||||
if (lastClass >= 0) {
|
||||
ClassMetadata clsData = classesMetadata.get(lastClass);
|
||||
clsData.methods = methods.getAll();
|
||||
methods.clear();
|
||||
}
|
||||
lastClass = classIndex;
|
||||
}
|
||||
int methodIndex = (int)exactMethod;
|
||||
methods.add(methodIndex);
|
||||
}
|
||||
if (lastClass >= 0) {
|
||||
ClassMetadata clsData = classesMetadata.get(lastClass);
|
||||
clsData.methods = methods.getAll();
|
||||
Arrays.sort(clsData.methods);
|
||||
}
|
||||
|
||||
int[] start = new int[exactMethods.length];
|
||||
Arrays.fill(start, -1);
|
||||
IntegerArray data = new IntegerArray(1);
|
||||
IntegerArray next = new IntegerArray(1);
|
||||
for (int i = 0; i < classesMetadata.size(); ++i) {
|
||||
ClassMetadata clsData = classesMetadata.get(i);
|
||||
clsData.parentId;
|
||||
if (clsData.parentId == null || clsData.methods == null) {
|
||||
continue;
|
||||
}
|
||||
for (int methodIndex : clsData.methods) {
|
||||
ClassMetadata superclsData = classesMetadata.get(clsData.parentId);
|
||||
Integer parentId = clsData.parentId;
|
||||
while (superclsData != null) {
|
||||
if (Arrays.binarySearch(superclsData.methods, methodIndex) >= 0) {
|
||||
int childMethod = getExactMethodIndex(i, methodIndex);
|
||||
int parentMethod = getExactMethodIndex(parentId, methodIndex);
|
||||
int ptr = start[parentMethod];
|
||||
start[parentMethod] = data.size();
|
||||
data.add(childMethod);
|
||||
next.add(ptr);
|
||||
break;
|
||||
}
|
||||
parentId = superclsData.parentId;
|
||||
superclsData = parentId != null ? classesMetadata.get(parentId) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MethodTree methodTree = new MethodTree();
|
||||
methodTree.offsets = new int[start.length + 1];
|
||||
methodTree.data = new int[data.size()];
|
||||
int index = 0;
|
||||
for (int i = 0; i < start.length; ++i) {
|
||||
int ptr = start[i];
|
||||
while (ptr != -1) {
|
||||
methodTree.data[index++] = data.get(ptr);
|
||||
ptr = next.get(ptr);
|
||||
}
|
||||
methodTree.offsets[i + 1] = index;
|
||||
}
|
||||
this.methodTree = methodTree;
|
||||
}
|
||||
|
||||
private Integer getExactMethodIndex(int classIndex, int methodIndex) {
|
||||
long entry = ((long)classIndex << 32) | methodIndex;
|
||||
return exactMethodMap.get(entry);
|
||||
}
|
||||
|
||||
class MethodEntrancesBuilder {
|
||||
|
@ -571,6 +688,7 @@ public class DebugInformation {
|
|||
static class ClassMetadata {
|
||||
Integer parentId;
|
||||
Map<Integer, Integer> fieldMap = new HashMap<>();
|
||||
int[] methods;
|
||||
}
|
||||
|
||||
static class CFG {
|
||||
|
|
|
@ -101,7 +101,8 @@ class DebugInformationReader {
|
|||
int line = 0;
|
||||
offsets.add(0);
|
||||
while (i < lines.length) {
|
||||
line += readUnsignedNumber();
|
||||
int passedLines = readUnsignedNumber();
|
||||
line += passedLines;
|
||||
int sz = readUnsignedNumber();
|
||||
if (sz == 0) {
|
||||
lines[i] = -1;
|
||||
|
@ -117,7 +118,9 @@ class DebugInformationReader {
|
|||
lines[i] = last;
|
||||
files[i++] = index + readNumber();
|
||||
}
|
||||
offsets.add(i);
|
||||
for (int j = 0; j < passedLines; ++j) {
|
||||
offsets.add(i);
|
||||
}
|
||||
}
|
||||
DebugInformation.CFG cfg = new DebugInformation.CFG();
|
||||
cfg.offsets = offsets.getAll();
|
||||
|
|
|
@ -63,7 +63,7 @@ public class Debugger {
|
|||
}
|
||||
|
||||
public void stepInto() {
|
||||
javaScriptDebugger.stepInto();
|
||||
step(true);
|
||||
}
|
||||
|
||||
public void stepOut() {
|
||||
|
@ -71,32 +71,54 @@ public class Debugger {
|
|||
}
|
||||
|
||||
public void stepOver() {
|
||||
step(false);
|
||||
}
|
||||
|
||||
private void step(boolean enterMethod) {
|
||||
CallFrame[] callStack = getCallStack();
|
||||
if (callStack == null || callStack.length == 0) {
|
||||
javaScriptDebugger.stepOver();
|
||||
if (enterMethod) {
|
||||
javaScriptDebugger.stepInto();
|
||||
} else {
|
||||
javaScriptDebugger.stepOver();
|
||||
}
|
||||
return;
|
||||
}
|
||||
CallFrame recentFrame = callStack[0];
|
||||
if (recentFrame.getLocation() == null || recentFrame.getLocation().getFileName() == null ||
|
||||
recentFrame.getLocation().getLine() < 0) {
|
||||
javaScriptDebugger.stepOver();
|
||||
if (enterMethod) {
|
||||
javaScriptDebugger.stepInto();
|
||||
} else {
|
||||
javaScriptDebugger.stepOver();
|
||||
}
|
||||
return;
|
||||
}
|
||||
Set<JavaScriptLocation> successors = new HashSet<>();
|
||||
for (int i = 0; i < callStack.length; ++i) {
|
||||
CallFrame frame = callStack[i];
|
||||
boolean exits = false;
|
||||
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;
|
||||
for (Map.Entry<String, DebugInformation> entry : debugInformationMap.entrySet()) {
|
||||
DebugInformation debugInfo = entry.getValue();
|
||||
SourceLocation[] following = debugInfo.getFollowingLines(frame.getLocation());
|
||||
if (following == null) {
|
||||
continue;
|
||||
if (following != null) {
|
||||
for (SourceLocation successor : following) {
|
||||
if (successor == null) {
|
||||
exits = true;
|
||||
} else {
|
||||
for (GeneratedLocation loc : debugInfo.getGeneratedLocations(successor)) {
|
||||
successors.add(new JavaScriptLocation(entry.getKey(), loc.getLine(), loc.getColumn()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (SourceLocation successor : debugInfo.getFollowingLines(frame.getLocation())) {
|
||||
if (successor == null) {
|
||||
exits = true;
|
||||
} else {
|
||||
for (GeneratedLocation loc : debugInfo.getGeneratedLocations(successor)) {
|
||||
if (enterMethod && callMethod != null) {
|
||||
for (MethodReference potentialMethod : debugInfo.getOverridingMethods(callMethod)) {
|
||||
for (GeneratedLocation loc : debugInfo.getMethodEntrances(potentialMethod)) {
|
||||
successors.add(new JavaScriptLocation(entry.getKey(), loc.getLine(), loc.getColumn()));
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +250,7 @@ public class Debugger {
|
|||
jsFrame.getLocation().getColumn()) : null;
|
||||
if (!empty || !wasEmpty) {
|
||||
VariableMap vars = new VariableMap(jsFrame.getVariables(), this, jsFrame.getLocation());
|
||||
frames.add(new CallFrame(loc, method, vars));
|
||||
frames.add(new CallFrame(jsFrame.getLocation(), loc, method, vars));
|
||||
}
|
||||
wasEmpty = empty;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user