Introduces another approach for setting temporary breakpoints at

methods' start lines when stepping in, due to bug in google chrome:
http://code.google.com/p/chromium/issues/detail?id=407105
This commit is contained in:
konsoletyper 2014-08-27 18:05:38 +04:00
parent 7cb3ce70c3
commit 7e1ff76c5d
4 changed files with 76 additions and 13 deletions

View File

@ -27,21 +27,26 @@ public class RecordArray {
private int[] data; private int[] data;
private int[] substart; private int[] substart;
private int[] subdata; private int[] subdata;
private int size;
RecordArray(int recordSize, int arraysPerRecord, int[] data, int[] substart, int[] subdata) { RecordArray(int recordSize, int arraysPerRecord, int size, int[] data, int[] substart, int[] subdata) {
this.recordSize = recordSize; this.recordSize = recordSize;
this.arraysPerRecord = arraysPerRecord; this.arraysPerRecord = arraysPerRecord;
this.size = size;
this.data = data; this.data = data;
this.substart = substart; this.substart = substart;
this.subdata = subdata; this.subdata = subdata;
} }
public Record get(int index) { public Record get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index " + index + " is outside of [0; " + size + ")");
}
return new Record(index * recordSize, index * arraysPerRecord); return new Record(index * recordSize, index * arraysPerRecord);
} }
public int size() { public int size() {
return data.length / recordSize; return size;
} }
public int getRecordSize() { public int getRecordSize() {

View File

@ -22,6 +22,7 @@ package org.teavm.common;
public class RecordArrayBuilder { public class RecordArrayBuilder {
private int recordSize; private int recordSize;
private int arraysPerRecord; private int arraysPerRecord;
private int size;
private IntegerArray data = new IntegerArray(1); private IntegerArray data = new IntegerArray(1);
private IntegerArray substart = new IntegerArray(1); private IntegerArray substart = new IntegerArray(1);
private IntegerArray subdata = new IntegerArray(1); private IntegerArray subdata = new IntegerArray(1);
@ -33,6 +34,9 @@ public class RecordArrayBuilder {
} }
public Record get(int index) { public Record get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index " + index + " is outside of [0; " + size + ")");
}
return new Record(index * recordSize, index * arraysPerRecord); return new Record(index * recordSize, index * arraysPerRecord);
} }
@ -45,11 +49,12 @@ public class RecordArrayBuilder {
for (int i = 0; i < arraysPerRecord; ++i) { for (int i = 0; i < arraysPerRecord; ++i) {
substart.add(-1); substart.add(-1);
} }
++size;
return new Record(offset, arrayOffset); return new Record(offset, arrayOffset);
} }
public int size() { public int size() {
return data.size() / recordSize; return size;
} }
public int getRecordSize() { public int getRecordSize() {
@ -71,7 +76,7 @@ public class RecordArrayBuilder {
} }
builtSubstart[i + 1] = builtSubdata.size(); builtSubstart[i + 1] = builtSubdata.size();
} }
return new RecordArray(recordSize, arraysPerRecord, data.getAll(), builtSubstart, builtSubdata.getAll()); return new RecordArray(recordSize, arraysPerRecord, size, data.getAll(), builtSubstart, builtSubdata.getAll());
} }
public class Record { public class Record {

View File

@ -18,6 +18,8 @@ package org.teavm.debugging;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import org.teavm.common.IntegerArray; import org.teavm.common.IntegerArray;
import org.teavm.common.RecordArray;
import org.teavm.common.RecordArrayBuilder;
import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -45,6 +47,7 @@ public class DebugInformation {
Mapping lineMapping; Mapping lineMapping;
Mapping callSiteMapping; Mapping callSiteMapping;
MultiMapping[] variableMappings; MultiMapping[] variableMappings;
RecordArray[] lineCallSites;
CFG[] controlFlowGraphs; CFG[] controlFlowGraphs;
List<ClassMetadata> classesMetadata; List<ClassMetadata> classesMetadata;
MethodEntrances methodEntrances; MethodEntrances methodEntrances;
@ -258,6 +261,24 @@ public class DebugInformation {
} }
} }
public MethodReference[] getCallSites(SourceLocation location) {
Integer fileIndex = fileNameMap.get(location.getFileName());
if (fileIndex == null) {
return new MethodReference[0];
}
RecordArray mapping = lineCallSites[fileIndex];
if (location.getLine() >= mapping.size()) {
return new MethodReference[0];
}
int[] callSiteIds = mapping.get(location.getLine()).getArray(0);
MethodReference[] methods = new MethodReference[callSiteIds.length];
for (int i = 0; i < callSiteIds.length; ++i) {
int exactMethodId = callSiteMapping.values[callSiteIds[i]];
methods[i] = getExactMethod(exactMethodId);
}
return methods;
}
private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) { private <T> T componentByKey(Mapping mapping, T[] values, GeneratedLocation location) {
int keyIndex = indexByKey(mapping, location); int keyIndex = indexByKey(mapping, location);
int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1; int valueIndex = keyIndex >= 0 ? mapping.values[keyIndex] : -1;
@ -283,6 +304,11 @@ public class DebugInformation {
return index >= 0 ? index : -index - 2; return index >= 0 ? index : -index - 2;
} }
private int valueByKey(Mapping mapping, GeneratedLocation location) {
int index = indexByKey(mapping, location);
return index >= 0 ? mapping.values[index] : -1;
}
private int indexByKey(MultiMapping mapping, GeneratedLocation location) { private int indexByKey(MultiMapping mapping, GeneratedLocation location) {
int index = Collections.binarySearch(mapping.keyList(), location); int index = Collections.binarySearch(mapping.keyList(), location);
return index >= 0 ? index : -index - 2; return index >= 0 ? index : -index - 2;
@ -307,6 +333,7 @@ public class DebugInformation {
rebuildFileDescriptions(); rebuildFileDescriptions();
rebuildEntrances(); rebuildEntrances();
rebuildMethodTree(); rebuildMethodTree();
rebuildLineCallSites();
} }
void rebuildMaps() { void rebuildMaps() {
@ -439,6 +466,32 @@ public class DebugInformation {
return exactMethodMap.get(entry); return exactMethodMap.get(entry);
} }
private void rebuildLineCallSites() {
lineCallSites = new RecordArray[fileNames.length];
RecordArrayBuilder[] builders = new RecordArrayBuilder[fileNames.length];
for (int i = 0; i < lineCallSites.length; ++i) {
builders[i] = new RecordArrayBuilder(0, 1);
}
for (int i = 0; i < callSiteMapping.lines.length; ++i) {
GeneratedLocation loc = callSiteMapping.key(i);
int methodId = callSiteMapping.values[i];
if (methodId >= 0) {
int line = valueByKey(lineMapping, loc);
int fileId = valueByKey(fileMapping, loc);
if (fileId >= 0 && line >= 0) {
RecordArrayBuilder builder = builders[fileId];
while (builder.size() <= line) {
builder.add();
}
builder.get(line).getArray(0).add(i);
}
}
}
for (int i = 0; i < lineCallSites.length; ++i) {
lineCallSites[i] = builders[i].build();
}
}
class MethodEntrancesBuilder { class MethodEntrancesBuilder {
int[] start; int[] start;
IntegerArray data; IntegerArray data;

View File

@ -98,21 +98,21 @@ public class Debugger {
for (CallFrame frame : callStack) { for (CallFrame frame : callStack) {
boolean exits; boolean exits;
String script = frame.originalLocation.getScript(); String script = frame.originalLocation.getScript();
GeneratedLocation genLoc = new GeneratedLocation(frame.originalLocation.getLine(),
frame.originalLocation.getColumn());
DebugInformation debugInfo = debugInformationMap.get(script); DebugInformation debugInfo = debugInformationMap.get(script);
if (frame.getLocation() != null && debugInfo != null) { if (frame.getLocation() != null && frame.getLocation().getFileName() != null &&
exits = false; frame.getLocation().getLine() >= 0 && debugInfo != null) {
MethodReference callMethod = debugInfo.getCallSite(genLoc); MethodReference[] callMethods = debugInfo.getCallSites(frame.getLocation());
exits = addFollowing(debugInfo, frame.getLocation(), script, new HashSet<SourceLocation>(), exits = addFollowing(debugInfo, frame.getLocation(), script, new HashSet<SourceLocation>(),
successors); successors);
if (enterMethod && callMethod != null) { if (enterMethod) {
for (MethodReference callMethod : callMethods) {
for (MethodReference potentialMethod : debugInfo.getOverridingMethods(callMethod)) { for (MethodReference potentialMethod : debugInfo.getOverridingMethods(callMethod)) {
for (GeneratedLocation loc : debugInfo.getMethodEntrances(potentialMethod)) { for (GeneratedLocation loc : debugInfo.getMethodEntrances(potentialMethod)) {
successors.add(new JavaScriptLocation(script, loc.getLine(), loc.getColumn())); successors.add(new JavaScriptLocation(script, loc.getLine(), loc.getColumn()));
} }
} }
} }
}
} else { } else {
exits = true; exits = true;
} }