mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-09 00:14:10 -08:00
Refactoring of debug information
This commit is contained in:
parent
88c47095a6
commit
45c336ebb8
|
@ -57,6 +57,18 @@ public class RecordArray {
|
||||||
return arraysPerRecord;
|
return arraysPerRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int[] cut(int index) {
|
||||||
|
if (index < 0 || index >= recordSize) {
|
||||||
|
throw new IndexOutOfBoundsException("Index " + index + " is outside of [0; " + recordSize + ")");
|
||||||
|
}
|
||||||
|
int[] result = new int[size];
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
result[i] = data[index];
|
||||||
|
index += recordSize;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public class Record {
|
public class Record {
|
||||||
int offset;
|
int offset;
|
||||||
int arrayOffset;
|
int arrayOffset;
|
||||||
|
|
|
@ -110,6 +110,13 @@ public class RecordArrayBuilder {
|
||||||
return data.get(index + offset);
|
return data.get(index + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void set(int index, int value) {
|
||||||
|
if (index >= recordSize) {
|
||||||
|
throw new IndexOutOfBoundsException("Index out of bounds: " + index + " of " + recordSize);
|
||||||
|
}
|
||||||
|
data.set(index + offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
return recordSize;
|
return recordSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,5 +20,40 @@ package org.teavm.debugging;
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public class ClassNameIterator {
|
public class ClassNameIterator {
|
||||||
|
private DebugInformation debugInformation;
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
ClassNameIterator(DebugInformation debugInformation) {
|
||||||
|
this.debugInformation = debugInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEndReached() {
|
||||||
|
return index < debugInformation.classMapping.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneratedLocation getLocation() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return DebugInformation.key(debugInformation.classMapping.get(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClassNameId() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return debugInformation.classMapping.get(index).get(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
int classNameId = getClassNameId();
|
||||||
|
return classNameId >= 0 ? debugInformation.getClassName(classNameId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class DebugInformation {
|
||||||
RecordArray methodMapping;
|
RecordArray methodMapping;
|
||||||
RecordArray lineMapping;
|
RecordArray lineMapping;
|
||||||
RecordArray callSiteMapping;
|
RecordArray callSiteMapping;
|
||||||
MultiMapping[] variableMappings;
|
RecordArray[] variableMappings;
|
||||||
RecordArray[] lineCallSites;
|
RecordArray[] lineCallSites;
|
||||||
CFG[] controlFlowGraphs;
|
CFG[] controlFlowGraphs;
|
||||||
List<ClassMetadata> classesMetadata;
|
List<ClassMetadata> classesMetadata;
|
||||||
|
@ -73,6 +73,71 @@ public class DebugInformation {
|
||||||
return fileNames[fileNameId];
|
return fileNames[fileNameId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getClassNames() {
|
||||||
|
return classNames.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName(int classNameId) {
|
||||||
|
return classNames[classNameId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodDescriptor[] getMethods() {
|
||||||
|
MethodDescriptor[] descriptors = new MethodDescriptor[methods.length];
|
||||||
|
for (int i = 0; i < descriptors.length; ++i) {
|
||||||
|
descriptors[i] = MethodDescriptor.parse(methods[i]);
|
||||||
|
}
|
||||||
|
return descriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodDescriptor getMethod(int methodId) {
|
||||||
|
return MethodDescriptor.parse(methods[methodId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodReference[] getExactMethods() {
|
||||||
|
MethodReference[] result = new MethodReference[exactMethods.length];
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = getExactMethod(i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 int getExactMethodId(int classNameId, int methodId) {
|
||||||
|
long full = ((long)classNameId << 32) | methodId;
|
||||||
|
Integer id = exactMethodMap.get(full);
|
||||||
|
return id != null ? id : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassNameIterator iterateOverClassNames() {
|
||||||
|
return new ClassNameIterator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodIterator iterateOverMethods() {
|
||||||
|
return new MethodIterator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExactMethodIterator iterateOverExactMethods() {
|
||||||
|
return new ExactMethodIterator(this);
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) {
|
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) {
|
||||||
Integer fileIndex = fileNameMap.get(fileName);
|
Integer fileIndex = fileNameMap.get(fileName);
|
||||||
if (fileIndex == null) {
|
if (fileIndex == null) {
|
||||||
|
@ -139,11 +204,11 @@ public class DebugInformation {
|
||||||
if (varIndex == null) {
|
if (varIndex == null) {
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
MultiMapping mapping = variableMappings[varIndex];
|
RecordArray mapping = variableMappings[varIndex];
|
||||||
if (mapping == null) {
|
if (mapping == null) {
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
return componentByKey(mapping, variableNames, location);
|
return componentSetByKey(mapping, variableNames, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceLocation[] getFollowingLines(SourceLocation location) {
|
public SourceLocation[] getFollowingLines(SourceLocation location) {
|
||||||
|
@ -212,7 +277,7 @@ public class DebugInformation {
|
||||||
case DebuggerCallSite.STATIC:
|
case DebuggerCallSite.STATIC:
|
||||||
return new DebuggerStaticCallSite(getExactMethod(data[0]));
|
return new DebuggerStaticCallSite(getExactMethod(data[0]));
|
||||||
case DebuggerCallSite.VIRTUAL:
|
case DebuggerCallSite.VIRTUAL:
|
||||||
return new DebuggerVirtualCallSite(getExactMethod(data[0]), data[1], variableNames[data[1]]);
|
return new DebuggerVirtualCallSite(getExactMethod(data[0]));
|
||||||
default:
|
default:
|
||||||
throw new AssertionError("Unrecognized call site type: " + type);
|
throw new AssertionError("Unrecognized call site type: " + type);
|
||||||
}
|
}
|
||||||
|
@ -227,26 +292,12 @@ public class DebugInformation {
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
return new GeneratedLocation[0];
|
return new GeneratedLocation[0];
|
||||||
}
|
}
|
||||||
return methodEntrances.getEntrances(index);
|
int[] data = methodEntrances.get(0).getArray(0);
|
||||||
}
|
GeneratedLocation[] entrances = new GeneratedLocation[data.length / 2];
|
||||||
|
for (int i = 0; i < entrances.length; ++i) {
|
||||||
private Integer getExactMethodIndex(MethodReference methodRef) {
|
entrances[i] = new GeneratedLocation(data[i * 2], data[i * 2 + 1]);
|
||||||
Integer classIndex = classNameMap.get(methodRef.getClassName());
|
|
||||||
if (classIndex == null) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
Integer methodIndex = methodMap.get(methodRef.getDescriptor().toString());
|
return entrances;
|
||||||
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) {
|
public MethodReference[] getDirectOverridingMethods(MethodReference methodRef) {
|
||||||
|
@ -300,16 +351,15 @@ public class DebugInformation {
|
||||||
return valueIndex >= 0 ? values[valueIndex] : null;
|
return valueIndex >= 0 ? values[valueIndex] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] componentByKey(MultiMapping mapping, String[] values, GeneratedLocation location) {
|
private String[] componentSetByKey(RecordArray mapping, String[] values, GeneratedLocation location) {
|
||||||
int keyIndex = indexByKey(mapping, location);
|
int keyIndex = indexByKey(mapping, location);
|
||||||
if (keyIndex < 0) {
|
if (keyIndex < 0) {
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
int start = mapping.offsets[keyIndex];
|
int[] valueIndexes = mapping.get(keyIndex).getArray(0);
|
||||||
int end = mapping.offsets[keyIndex + 1];
|
String[] result = new String[valueIndexes.length];
|
||||||
String[] result = new String[end - start];
|
|
||||||
for (int i = 0; i < result.length; ++i) {
|
for (int i = 0; i < result.length; ++i) {
|
||||||
result[i] = values[mapping.data[i + start]];
|
result[i] = values[valueIndexes[i]];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -324,11 +374,6 @@ public class DebugInformation {
|
||||||
return index >= 0 ? mapping.get(index).get(2) : -1;
|
return index >= 0 ? mapping.get(index).get(2) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int indexByKey(MultiMapping mapping, GeneratedLocation location) {
|
|
||||||
int index = Collections.binarySearch(mapping.keyList(), location);
|
|
||||||
return index >= 0 ? index : -index - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(OutputStream output) throws IOException {
|
public void write(OutputStream output) throws IOException {
|
||||||
DebugInformationWriter writer = new DebugInformationWriter(new DataOutputStream(output));
|
DebugInformationWriter writer = new DebugInformationWriter(new DataOutputStream(output));
|
||||||
writer.write(this);
|
writer.write(this);
|
||||||
|
@ -372,48 +417,56 @@ public class DebugInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rebuildFileDescriptions() {
|
void rebuildFileDescriptions() {
|
||||||
FileDescriptionBuilder builder = new FileDescriptionBuilder(fileNames.length);
|
RecordArrayBuilder[] builders = new RecordArrayBuilder[fileNames.length];
|
||||||
int fileIndex = 0;
|
for (int i = 0; i < builders.length; ++i) {
|
||||||
int lineIndex = 0;
|
builders[i] = new RecordArrayBuilder(0, 1);
|
||||||
int currentFile = -1;
|
}
|
||||||
int currentLine = -1;
|
for (SourceLocationIterator iter = iterateOverSourceLocations(); !iter.isEndReached(); iter.next()) {
|
||||||
while (fileIndex < fileMapping.size() && lineIndex < lineMapping.size()) {
|
if (iter.getFileNameId() >= 0 && iter.getLine() >= 0) {
|
||||||
RecordArray.Record fileRec = fileMapping.get(fileIndex);
|
RecordArrayBuilder builder = builders[iter.getFileNameId()];
|
||||||
RecordArray.Record lineRec = lineMapping.get(lineIndex);
|
while (builder.size() <= iter.getLine()) {
|
||||||
GeneratedLocation fileLoc = key(fileRec);
|
builder.add();
|
||||||
GeneratedLocation lineLoc = key(lineRec);
|
}
|
||||||
int cmp = fileLoc.compareTo(lineLoc);
|
GeneratedLocation loc = iter.getLocation();
|
||||||
if (cmp < 0) {
|
RecordArrayBuilder.RecordSubArray array = builder.get(iter.getLine()).getArray(0);
|
||||||
currentFile = fileRec.get(2);
|
array.add(loc.getLine());
|
||||||
fileIndex++;
|
array.add(loc.getColumn());
|
||||||
} else if (cmp > 0){
|
|
||||||
currentLine = lineRec.get(2);
|
|
||||||
lineIndex++;
|
|
||||||
} else {
|
|
||||||
currentFile = fileRec.get(2);
|
|
||||||
currentLine = lineRec.get(2);
|
|
||||||
fileIndex++;
|
|
||||||
lineIndex++;
|
|
||||||
}
|
}
|
||||||
builder.emit(fileLoc.getLine(), fileLoc.getColumn(), currentFile, currentLine);
|
|
||||||
}
|
}
|
||||||
while (fileIndex < fileMapping.size()) {
|
fileDescriptions = new RecordArray[builders.length];
|
||||||
RecordArray.Record fileRec = fileMapping.get(fileIndex++);
|
for (int i = 0; i < fileDescriptions.length; ++i) {
|
||||||
builder.emit(fileRec.get(0), fileRec.get(1), fileRec.get(2), currentLine);
|
fileDescriptions[i] = builders[i].build();
|
||||||
}
|
}
|
||||||
while (lineIndex < lineMapping.size()) {
|
|
||||||
RecordArray.Record lineRec = lineMapping.get(lineIndex++);
|
|
||||||
builder.emit(lineRec.get(0), lineRec.get(1), currentFile, lineRec.get(2));
|
|
||||||
}
|
|
||||||
fileDescriptions = builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rebuildEntrances() {
|
void rebuildEntrances() {
|
||||||
RecordArrayBuilder builder = new RecordArrayBuilder(0, 1);
|
RecordArrayBuilder builder = new RecordArrayBuilder(0, 1);
|
||||||
for (SourceLocationIterator iter = iterateOverSourceLocations(); !iter.isEndReached(); iter.next()) {
|
for (int i = 0; i < exactMethods.length; ++i) {
|
||||||
iter.getLocation();
|
builder.add();
|
||||||
|
}
|
||||||
|
GeneratedLocation prevLocation = new GeneratedLocation(0, 0);
|
||||||
|
MethodReference prevMethod = null;
|
||||||
|
for (ExactMethodIterator iter = iterateOverExactMethods(); !iter.isEndReached(); iter.next()) {
|
||||||
|
int id = iter.getExactMethodId();
|
||||||
|
if (prevMethod != null) {
|
||||||
|
int lineIndex = Math.max(0, indexByKey(lineMapping, prevLocation));
|
||||||
|
while (lineIndex < 0) {
|
||||||
|
if (key(lineMapping.get(lineIndex)).compareTo(iter.getLocation()) >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int line = lineMapping.get(0).get(2);
|
||||||
|
if (line >= 0) {
|
||||||
|
GeneratedLocation firstLineLoc = key(lineMapping.get(lineIndex));
|
||||||
|
RecordArrayBuilder.RecordSubArray array = builder.get(id).getArray(0);
|
||||||
|
array.add(firstLineLoc.getLine());
|
||||||
|
array.add(firstLineLoc.getColumn());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevMethod = iter.getExactMethod();
|
||||||
|
prevLocation = iter.getLocation();
|
||||||
}
|
}
|
||||||
methodEntrances = new MethodEntrancesBuilder().build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rebuildMethodTree() {
|
void rebuildMethodTree() {
|
||||||
|
@ -516,188 +569,10 @@ public class DebugInformation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MethodEntrancesBuilder {
|
|
||||||
int[] start;
|
|
||||||
IntegerArray data;
|
|
||||||
IntegerArray next;
|
|
||||||
int methodIndex;
|
|
||||||
int classIndex;
|
|
||||||
|
|
||||||
public MethodEntrances build() {
|
|
||||||
methodIndex = -1;
|
|
||||||
classIndex = -1;
|
|
||||||
start = new int[exactMethods.length];
|
|
||||||
Arrays.fill(start, -1);
|
|
||||||
data = new IntegerArray(0);
|
|
||||||
next = new IntegerArray(0);
|
|
||||||
int methodMappingIndex = 0;
|
|
||||||
int classMappingIndex = 0;
|
|
||||||
GeneratedLocation previousLocation = new GeneratedLocation(0, 0);
|
|
||||||
while (methodMappingIndex < methodMapping.lines.length &&
|
|
||||||
classMappingIndex < classMapping.lines.length) {
|
|
||||||
GeneratedLocation methodLoc = new GeneratedLocation(methodMapping.lines[methodMappingIndex],
|
|
||||||
methodMapping.columns[methodMappingIndex]);
|
|
||||||
GeneratedLocation classLoc = new GeneratedLocation(classMapping.lines[classMappingIndex],
|
|
||||||
classMapping.columns[classMappingIndex]);
|
|
||||||
int cmp = methodLoc.compareTo(classLoc);
|
|
||||||
if (cmp < 0) {
|
|
||||||
addMethodEntrance(previousLocation, methodLoc);
|
|
||||||
previousLocation = methodLoc;
|
|
||||||
methodIndex = methodMapping.values[methodMappingIndex++];
|
|
||||||
} else if (cmp > 0) {
|
|
||||||
addMethodEntrance(previousLocation, classLoc);
|
|
||||||
previousLocation = classLoc;
|
|
||||||
classIndex = classMapping.values[classMappingIndex++];
|
|
||||||
} else {
|
|
||||||
addMethodEntrance(previousLocation, classLoc);
|
|
||||||
previousLocation = classLoc;
|
|
||||||
methodIndex = methodMapping.values[methodMappingIndex++];
|
|
||||||
classIndex = classMapping.values[classMappingIndex++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (methodMappingIndex < methodMapping.lines.length) {
|
|
||||||
GeneratedLocation methodLoc = new GeneratedLocation(methodMapping.lines[methodMappingIndex],
|
|
||||||
methodMapping.columns[methodMappingIndex]);
|
|
||||||
addMethodEntrance(previousLocation, methodLoc);
|
|
||||||
previousLocation = methodLoc;
|
|
||||||
methodIndex = methodMapping.values[methodMappingIndex++];
|
|
||||||
}
|
|
||||||
while (classMappingIndex < classMapping.lines.length) {
|
|
||||||
GeneratedLocation classLoc = new GeneratedLocation(classMapping.lines[classMappingIndex],
|
|
||||||
classMapping.columns[classMappingIndex]);
|
|
||||||
addMethodEntrance(previousLocation, classLoc);
|
|
||||||
previousLocation = classLoc;
|
|
||||||
classIndex = classMapping.values[classMappingIndex++];
|
|
||||||
}
|
|
||||||
return assemble();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addMethodEntrance(GeneratedLocation location, GeneratedLocation limit) {
|
|
||||||
if (classIndex < 0 || methodIndex < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long exactMethod = ((long)classIndex << 32) | methodIndex;
|
|
||||||
Integer exactMethodIndex = exactMethodMap.get(exactMethod);
|
|
||||||
if (exactMethodIndex == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lineIndex = indexByKey(lineMapping, location);
|
|
||||||
if (lineIndex < 0) {
|
|
||||||
lineIndex = 0;
|
|
||||||
}
|
|
||||||
int line = -1;
|
|
||||||
while (lineIndex < lineMapping.values.length) {
|
|
||||||
location = new GeneratedLocation(lineMapping.lines[lineIndex], lineMapping.columns[lineIndex]);
|
|
||||||
if (location.compareTo(limit) >= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (lineMapping.values[lineIndex] >= 0) {
|
|
||||||
line = lineMapping.values[lineIndex];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++lineIndex;
|
|
||||||
}
|
|
||||||
if (line == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ptr = start[exactMethodIndex];
|
|
||||||
start[exactMethodIndex] = data.size();
|
|
||||||
next.add(ptr);
|
|
||||||
ptr = data.size();
|
|
||||||
data.add(location.getColumn());
|
|
||||||
next.add(ptr);
|
|
||||||
start[exactMethodIndex] = data.size();
|
|
||||||
data.add(location.getLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
private MethodEntrances assemble() {
|
|
||||||
MethodEntrances entrances = new MethodEntrances();
|
|
||||||
entrances.offsets = new int[start.length + 1];
|
|
||||||
entrances.data = new int[data.size()];
|
|
||||||
int index = 0;
|
|
||||||
for (int i = 0; i < start.length; ++i) {
|
|
||||||
int ptr = start[i];
|
|
||||||
while (ptr != -1) {
|
|
||||||
entrances.data[index++] = data.get(ptr);
|
|
||||||
ptr = next.get(ptr);
|
|
||||||
}
|
|
||||||
entrances.offsets[i + 1] = index;
|
|
||||||
}
|
|
||||||
return entrances;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class FileDescriptionBuilder {
|
|
||||||
RecordArrayBuilder[] files;
|
|
||||||
int lastFileIndex = -1;
|
|
||||||
int lastSourceLine = -1;
|
|
||||||
|
|
||||||
public FileDescriptionBuilder(int size) {
|
|
||||||
files = new RecordArrayBuilder[size];
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
files[i] = new RecordArrayBuilder(0, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void emit(int line, int column, int fileIndex, int sourceLine) {
|
|
||||||
if (sourceLine == -1 || fileIndex == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (lastFileIndex == fileIndex && lastSourceLine == sourceLine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastFileIndex = fileIndex;
|
|
||||||
lastSourceLine = sourceLine;
|
|
||||||
RecordArrayBuilder proto = files[fileIndex];
|
|
||||||
while (proto.size() <= sourceLine) {
|
|
||||||
proto.add();
|
|
||||||
}
|
|
||||||
RecordArrayBuilder.RecordSubArray array = proto.get(sourceLine).getArray(0);
|
|
||||||
array.add(line);
|
|
||||||
array.add(column);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordArray[] build() {
|
|
||||||
RecordArray[] descriptions = new RecordArray[files.length];
|
|
||||||
for (int i = 0; i < files.length; ++i) {
|
|
||||||
descriptions[i] = files[i].build();
|
|
||||||
}
|
|
||||||
return descriptions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GeneratedLocation key(RecordArray.Record record) {
|
static GeneratedLocation key(RecordArray.Record record) {
|
||||||
return new GeneratedLocation(record.get(0), record.get(1));
|
return new GeneratedLocation(record.get(0), record.get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MultiMapping {
|
|
||||||
int[] lines;
|
|
||||||
int[] columns;
|
|
||||||
int[] offsets;
|
|
||||||
int[] data;
|
|
||||||
|
|
||||||
public MultiMapping(int[] lines, int[] columns, int[] offsets, int[] data) {
|
|
||||||
this.lines = lines;
|
|
||||||
this.columns = columns;
|
|
||||||
this.offsets = offsets;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocationList keyList() {
|
|
||||||
return new LocationList(lines, columns);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return lines.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeneratedLocation key(int index) {
|
|
||||||
return new GeneratedLocation(lines[index], columns[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class LocationList extends AbstractList<GeneratedLocation> {
|
static class LocationList extends AbstractList<GeneratedLocation> {
|
||||||
private RecordArray recordArray;
|
private RecordArray recordArray;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ package org.teavm.debugging;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.teavm.codegen.LocationProvider;
|
import org.teavm.codegen.LocationProvider;
|
||||||
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;
|
||||||
|
|
||||||
|
@ -35,12 +37,12 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
private MappedList variableNames = new MappedList();
|
private MappedList variableNames = new MappedList();
|
||||||
private List<Long> exactMethods = new ArrayList<>();
|
private List<Long> exactMethods = new ArrayList<>();
|
||||||
private Map<Long, Integer> exactMethodMap = new HashMap<>();
|
private Map<Long, Integer> exactMethodMap = new HashMap<>();
|
||||||
private Mapping fileMapping = new Mapping();
|
private RecordArrayBuilder fileMapping = new RecordArrayBuilder(3, 0);
|
||||||
private Mapping lineMapping = new Mapping();
|
private RecordArrayBuilder lineMapping = new RecordArrayBuilder(3, 0);
|
||||||
private Mapping classMapping = new Mapping();
|
private RecordArrayBuilder classMapping = new RecordArrayBuilder(3, 0);
|
||||||
private Mapping methodMapping = new Mapping();
|
private RecordArrayBuilder methodMapping = new RecordArrayBuilder(3, 0);
|
||||||
private Mapping callSiteMapping = new Mapping();
|
private RecordArrayBuilder callSiteMapping = new RecordArrayBuilder(3, 1);
|
||||||
private Map<Integer, MultiMapping> variableMappings = new HashMap<>();
|
private Map<Integer, RecordArrayBuilder> variableMappings = new HashMap<>();
|
||||||
private MethodDescriptor currentMethod;
|
private MethodDescriptor currentMethod;
|
||||||
private String currentClass;
|
private String currentClass;
|
||||||
private String currentFileName;
|
private String currentFileName;
|
||||||
|
@ -63,21 +65,40 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
debugInformation = null;
|
debugInformation = null;
|
||||||
int fileIndex = files.index(fileName);
|
int fileIndex = files.index(fileName);
|
||||||
if (!Objects.equals(currentFileName, fileName)) {
|
if (!Objects.equals(currentFileName, fileName)) {
|
||||||
fileMapping.add(locationProvider, fileIndex, true);
|
add(fileMapping, fileIndex);
|
||||||
currentFileName = fileName;
|
currentFileName = fileName;
|
||||||
}
|
}
|
||||||
if (currentLine != line) {
|
if (currentLine != line) {
|
||||||
lineMapping.add(locationProvider, line, true);
|
add(lineMapping, line);
|
||||||
currentLine = line;
|
currentLine = line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RecordArrayBuilder.Record add(RecordArrayBuilder builder) {
|
||||||
|
if (builder.size() > 1) {
|
||||||
|
RecordArrayBuilder.Record lastRecord = builder.get(builder.size() - 1);
|
||||||
|
if (lastRecord.get(0) == locationProvider.getLine() && lastRecord.get(1) == locationProvider.getColumn()) {
|
||||||
|
return lastRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RecordArrayBuilder.Record record = builder.add();
|
||||||
|
record.set(0, locationProvider.getLine());
|
||||||
|
record.set(1, locationProvider.getColumn());
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RecordArrayBuilder.Record add(RecordArrayBuilder builder, int value) {
|
||||||
|
RecordArrayBuilder.Record record = add(builder);
|
||||||
|
record.set(2, value);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emitClass(String className) {
|
public void emitClass(String className) {
|
||||||
debugInformation = null;
|
debugInformation = null;
|
||||||
int classIndex = classes.index(className);
|
int classIndex = classes.index(className);
|
||||||
if (!Objects.equals(className, currentClass)) {
|
if (!Objects.equals(className, currentClass)) {
|
||||||
classMapping.add(locationProvider, classIndex, true);
|
add(classMapping, classIndex);
|
||||||
currentClass = className;
|
currentClass = className;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +108,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
debugInformation = null;
|
debugInformation = null;
|
||||||
int methodIndex = methods.index(method != null ? method.toString() : null);
|
int methodIndex = methods.index(method != null ? method.toString() : null);
|
||||||
if (!Objects.equals(method, currentMethod)) {
|
if (!Objects.equals(method, currentMethod)) {
|
||||||
methodMapping.add(locationProvider, methodIndex, true);
|
add(methodMapping, methodIndex);
|
||||||
currentMethod = method;
|
currentMethod = method;
|
||||||
}
|
}
|
||||||
if (currentClass != null) {
|
if (currentClass != null) {
|
||||||
|
@ -108,19 +129,42 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
}
|
}
|
||||||
Arrays.sort(sourceIndexes);
|
Arrays.sort(sourceIndexes);
|
||||||
int generatedIndex = variableNames.index(generatedName);
|
int generatedIndex = variableNames.index(generatedName);
|
||||||
MultiMapping mapping = variableMappings.get(generatedIndex);
|
RecordArrayBuilder mapping = variableMappings.get(generatedIndex);
|
||||||
if (mapping == null) {
|
if (mapping == null) {
|
||||||
mapping = new MultiMapping();
|
mapping = new RecordArrayBuilder(2, 1);
|
||||||
variableMappings.put(generatedIndex, mapping);
|
variableMappings.put(generatedIndex, mapping);
|
||||||
}
|
}
|
||||||
mapping.add(locationProvider, sourceIndexes);
|
|
||||||
|
RecordArrayBuilder.Record record = add(mapping);
|
||||||
|
RecordArrayBuilder.RecordSubArray array = record.getArray(0);
|
||||||
|
for (int sourceIndex : sourceIndexes) {
|
||||||
|
array.add(sourceIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeferredCallSite emitCallSite() {
|
public DeferredCallSite emitCallSite() {
|
||||||
|
final RecordArrayBuilder.Record record = add(callSiteMapping, DebuggerCallSite.NONE);
|
||||||
DeferredCallSite callSite = new DeferredCallSite() {
|
DeferredCallSite callSite = new DeferredCallSite() {
|
||||||
int index = callSiteMapping.values.size();
|
@Override
|
||||||
@Override public void setMethod(MethodReference method) {
|
public void setVirtualMethod(MethodReference method) {
|
||||||
|
record.set(2, DebuggerCallSite.VIRTUAL);
|
||||||
|
RecordArrayBuilder.RecordSubArray array = record.getArray(0);
|
||||||
|
array.clear();
|
||||||
|
array.add(getExactMethodIndex(method));
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setStaticMethod(MethodReference method) {
|
||||||
|
record.set(2, DebuggerCallSite.STATIC);
|
||||||
|
RecordArrayBuilder.RecordSubArray array = record.getArray(0);
|
||||||
|
array.clear();
|
||||||
|
array.add(getExactMethodIndex(method));
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void clean() {
|
||||||
|
record.set(2, DebuggerCallSite.NONE);
|
||||||
|
}
|
||||||
|
private int getExactMethodIndex(MethodReference method) {
|
||||||
int methodIndex = methods.index(method.getDescriptor().toString());
|
int methodIndex = methods.index(method.getDescriptor().toString());
|
||||||
int classIndex = classes.index(method.getClassName());
|
int classIndex = classes.index(method.getClassName());
|
||||||
long fullIndex = ((long)classIndex << 32) | methodIndex;
|
long fullIndex = ((long)classIndex << 32) | methodIndex;
|
||||||
|
@ -130,18 +174,12 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
exactMethodMap.put(fullIndex, exactMethodIndex);
|
exactMethodMap.put(fullIndex, exactMethodIndex);
|
||||||
exactMethods.add(fullIndex);
|
exactMethods.add(fullIndex);
|
||||||
}
|
}
|
||||||
callSiteMapping.values.set(index, exactMethodIndex);
|
return exactMethodIndex;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
callSiteMapping.add(locationProvider, -1, false);
|
|
||||||
return callSite;
|
return callSite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void emitEmptyCallSite() {
|
|
||||||
callSiteMapping.add(locationProvider, -1, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addClass(String className, String parentName) {
|
public void addClass(String className, String parentName) {
|
||||||
int classIndex = classes.index(className);
|
int classIndex = classes.index(className);
|
||||||
|
@ -181,6 +219,43 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RecordArrayBuilder compress(RecordArrayBuilder builder) {
|
||||||
|
int lastValue = 0;
|
||||||
|
RecordArrayBuilder compressed = new RecordArrayBuilder(builder.getRecordSize(), builder.getArraysPerRecord());
|
||||||
|
for (int i = 0; i < builder.size(); ++i) {
|
||||||
|
RecordArrayBuilder.Record record = builder.get(i);
|
||||||
|
if (i == 0 || lastValue != record.get(2)) {
|
||||||
|
RecordArrayBuilder.Record compressedRecord = compressed.add();
|
||||||
|
for (int j = 0; j < builder.getRecordSize(); ++j) {
|
||||||
|
compressedRecord.set(j, record.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compressAndSortArrays(RecordArrayBuilder builder) {
|
||||||
|
for (int i = 0; i < builder.size(); ++i) {
|
||||||
|
RecordArrayBuilder.Record record = builder.get(i);
|
||||||
|
for (int j = 0; j < builder.getArraysPerRecord(); ++j) {
|
||||||
|
RecordArrayBuilder.RecordSubArray array = record.getArray(j);
|
||||||
|
int[] data = array.getData();
|
||||||
|
Arrays.sort(data);
|
||||||
|
array.clear();
|
||||||
|
if (data.length > 0) {
|
||||||
|
int last = data[0];
|
||||||
|
array.add(last);
|
||||||
|
for (int k = 1; k < data.length; ++k) {
|
||||||
|
if (data[k] != last) {
|
||||||
|
last = data[k];
|
||||||
|
array.add(last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public DebugInformation getDebugInformation() {
|
public DebugInformation getDebugInformation() {
|
||||||
if (debugInformation == null) {
|
if (debugInformation == null) {
|
||||||
debugInformation = new DebugInformation();
|
debugInformation = new DebugInformation();
|
||||||
|
@ -196,14 +271,15 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
}
|
}
|
||||||
debugInformation.exactMethodMap = new HashMap<>(exactMethodMap);
|
debugInformation.exactMethodMap = new HashMap<>(exactMethodMap);
|
||||||
|
|
||||||
debugInformation.fileMapping = fileMapping.build();
|
debugInformation.fileMapping = compress(fileMapping).build();
|
||||||
debugInformation.lineMapping = lineMapping.build();
|
debugInformation.lineMapping = compress(lineMapping).build();
|
||||||
debugInformation.classMapping = classMapping.build();
|
debugInformation.classMapping = compress(classMapping).build();
|
||||||
debugInformation.methodMapping = methodMapping.build();
|
debugInformation.methodMapping = compress(methodMapping).build();
|
||||||
debugInformation.callSiteMapping = callSiteMapping.build();
|
debugInformation.callSiteMapping = callSiteMapping.build();
|
||||||
debugInformation.variableMappings = new DebugInformation.MultiMapping[variableNames.list.size()];
|
debugInformation.variableMappings = new RecordArray[variableNames.list.size()];
|
||||||
for (int var : variableMappings.keySet()) {
|
for (int var : variableMappings.keySet()) {
|
||||||
MultiMapping mapping = variableMappings.get(var);
|
RecordArrayBuilder mapping = variableMappings.get(var);
|
||||||
|
compressAndSortArrays(mapping);
|
||||||
debugInformation.variableMappings[var] = mapping.build();
|
debugInformation.variableMappings[var] = mapping.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,107 +309,6 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
return debugInformation;
|
return debugInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Mapping {
|
|
||||||
IntegerArray lines = new IntegerArray(1);
|
|
||||||
IntegerArray columns = new IntegerArray(1);
|
|
||||||
IntegerArray values = new IntegerArray(1);
|
|
||||||
|
|
||||||
public void add(LocationProvider location, int value, boolean merge) {
|
|
||||||
if (merge && lines.size() > 1) {
|
|
||||||
int last = lines.size() - 1;
|
|
||||||
if (lines.get(last) == location.getLine() && columns.get(last) == location.getColumn()) {
|
|
||||||
values.set(last, value);
|
|
||||||
// TODO: check why this gives an invalid result
|
|
||||||
/*if (values.get(last) == values.get(last - 1)) {
|
|
||||||
values.remove(last);
|
|
||||||
lines.remove(last);
|
|
||||||
columns.remove(last);
|
|
||||||
}*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lines.add(location.getLine());
|
|
||||||
columns.add(location.getColumn());
|
|
||||||
values.add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugInformation.Mapping build() {
|
|
||||||
return new DebugInformation.Mapping(lines.getAll(), columns.getAll(), values.getAll());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class MultiMapping {
|
|
||||||
IntegerArray lines = new IntegerArray(1);
|
|
||||||
IntegerArray columns = new IntegerArray(1);
|
|
||||||
IntegerArray offsets = new IntegerArray(1);
|
|
||||||
IntegerArray data = new IntegerArray(1);
|
|
||||||
|
|
||||||
public MultiMapping() {
|
|
||||||
offsets.add(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(LocationProvider location, int[] values) {
|
|
||||||
if (lines.size() > 1) {
|
|
||||||
int last = lines.size() - 1;
|
|
||||||
if (lines.get(last) == location.getLine() && columns.get(last) == location.getColumn()) {
|
|
||||||
addToLast(values);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lines.add(location.getLine());
|
|
||||||
columns.add(location.getColumn());
|
|
||||||
data.addAll(values);
|
|
||||||
offsets.add(data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addToLast(int[] values) {
|
|
||||||
int start = offsets.get(offsets.size() - 2);
|
|
||||||
int end = offsets.get(offsets.size() - 1);
|
|
||||||
int[] existing = data.getRange(start, end);
|
|
||||||
values = merge(existing, values);
|
|
||||||
if (values.length == existing.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data.remove(start, end - start);
|
|
||||||
data.addAll(values);
|
|
||||||
offsets.set(offsets.size() - 1, data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] merge(int[] a, int[] b) {
|
|
||||||
int[] result = new int[a.length + b.length];
|
|
||||||
int i = 0;
|
|
||||||
int j = 0;
|
|
||||||
int k = 0;
|
|
||||||
while (i < a.length && j < b.length) {
|
|
||||||
int p = a[i];
|
|
||||||
int q = b[j];
|
|
||||||
if (p == q) {
|
|
||||||
result[k++] = p;
|
|
||||||
++i;
|
|
||||||
++j;
|
|
||||||
} else if (p < q) {
|
|
||||||
result[k++] = p;
|
|
||||||
++i;
|
|
||||||
} else {
|
|
||||||
result[k++] = q;
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (i < a.length) {
|
|
||||||
result[k++] = a[i++];
|
|
||||||
}
|
|
||||||
while (j < b.length) {
|
|
||||||
result[k++] = b[j++];
|
|
||||||
}
|
|
||||||
return k < result.length ? Arrays.copyOf(result, k) : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DebugInformation.MultiMapping build() {
|
|
||||||
return new DebugInformation.MultiMapping(lines.getAll(), columns.getAll(), offsets.getAll(),
|
|
||||||
data.getAll());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class MappedList {
|
static class MappedList {
|
||||||
private List<String> list = new ArrayList<>();
|
private List<String> list = new ArrayList<>();
|
||||||
private Map<String, Integer> map = new HashMap<>();
|
private Map<String, Integer> map = new HashMap<>();
|
||||||
|
|
|
@ -35,8 +35,6 @@ public interface DebugInformationEmitter {
|
||||||
|
|
||||||
DeferredCallSite emitCallSite();
|
DeferredCallSite emitCallSite();
|
||||||
|
|
||||||
void emitEmptyCallSite();
|
|
||||||
|
|
||||||
void addClass(String className, String parentName);
|
void addClass(String className, String parentName);
|
||||||
|
|
||||||
void addField(String fieldName, String jsName);
|
void addField(String fieldName, String jsName);
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.teavm.common.RecordArray;
|
||||||
import org.teavm.debugging.DebugInformation.ClassMetadata;
|
import org.teavm.debugging.DebugInformation.ClassMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,13 +58,13 @@ class DebugInformationWriter {
|
||||||
int lastVar = 0;
|
int lastVar = 0;
|
||||||
writeUnsignedNumber(nonNullVariableMappings(debugInfo));
|
writeUnsignedNumber(nonNullVariableMappings(debugInfo));
|
||||||
for (int i = 0; i < debugInfo.variableMappings.length; ++i) {
|
for (int i = 0; i < debugInfo.variableMappings.length; ++i) {
|
||||||
DebugInformation.MultiMapping mapping = debugInfo.variableMappings[i];
|
RecordArray mapping = debugInfo.variableMappings[i];
|
||||||
if (mapping == null) {
|
if (mapping == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
writeUnsignedNumber(i - lastVar);
|
writeUnsignedNumber(i - lastVar);
|
||||||
lastVar = i;
|
lastVar = i;
|
||||||
writeMapping(mapping);
|
writeMultiMapping(mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +115,8 @@ class DebugInformationWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeMapping(DebugInformation.MultiMapping mapping) throws IOException {
|
private void writeLinesAndColumns(RecordArray mapping) throws IOException {
|
||||||
int[] lines = mapping.lines.clone();
|
int[] lines = mapping.cut(0);
|
||||||
int last = 0;
|
int last = 0;
|
||||||
for (int i = 0; i < lines.length; ++i) {
|
for (int i = 0; i < lines.length; ++i) {
|
||||||
int next = lines[i];
|
int next = lines[i];
|
||||||
|
@ -124,36 +125,36 @@ class DebugInformationWriter {
|
||||||
}
|
}
|
||||||
writeRle(lines);
|
writeRle(lines);
|
||||||
resetRelativeNumber();
|
resetRelativeNumber();
|
||||||
for (int i = 0; i < mapping.columns.length; ++i) {
|
int[] columns = mapping.cut(1);
|
||||||
writeRelativeNumber(mapping.columns[i]);
|
int lastLine = -1;
|
||||||
}
|
for (int i = 0; i < columns.length; ++i) {
|
||||||
int lastOffset = 0;
|
if (lastLine != mapping.get(i).get(0)) {
|
||||||
for (int i = 1; i < mapping.offsets.length; ++i) {
|
resetRelativeNumber();
|
||||||
writeUnsignedNumber(mapping.offsets[i] - lastOffset);
|
lastLine = mapping.get(i).get(0);
|
||||||
lastOffset = mapping.offsets[i];
|
}
|
||||||
}
|
writeRelativeNumber(columns[i]);
|
||||||
resetRelativeNumber();
|
|
||||||
for (int i = 0; i < mapping.data.length; ++i) {
|
|
||||||
writeRelativeNumber(mapping.data[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeMapping(DebugInformation.Mapping mapping) throws IOException {
|
private void writeMultiMapping(RecordArray mapping) throws IOException {
|
||||||
int[] lines = mapping.lines.clone();
|
writeLinesAndColumns(mapping);
|
||||||
int last = 0;
|
for (int i = 0; i < mapping.size(); ++i) {
|
||||||
for (int i = 0; i < lines.length; ++i) {
|
int[] array = mapping.get(0).getArray(0);
|
||||||
int next = lines[i];
|
writeUnsignedNumber(array.length);
|
||||||
lines[i] -= last;
|
int lastNumber = 0;
|
||||||
last = next;
|
for (int elem : array) {
|
||||||
|
writeUnsignedNumber(elem - lastNumber);
|
||||||
|
lastNumber = elem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writeRle(lines);
|
}
|
||||||
|
|
||||||
|
private void writeMapping(RecordArray mapping) throws IOException {
|
||||||
|
writeLinesAndColumns(mapping);
|
||||||
resetRelativeNumber();
|
resetRelativeNumber();
|
||||||
for (int i = 0; i < mapping.columns.length; ++i) {
|
int[] values = mapping.cut(2);
|
||||||
writeRelativeNumber(mapping.columns[i]);
|
for (int i = 0; i < values.length; ++i) {
|
||||||
}
|
writeRelativeNumber(values[i]);
|
||||||
resetRelativeNumber();
|
|
||||||
for (int i = 0; i < mapping.values.length; ++i) {
|
|
||||||
writeRelativeNumber(mapping.values[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,16 +101,14 @@ public class Debugger {
|
||||||
DebugInformation debugInfo = debugInformationMap.get(script);
|
DebugInformation debugInfo = debugInformationMap.get(script);
|
||||||
if (frame.getLocation() != null && frame.getLocation().getFileName() != null &&
|
if (frame.getLocation() != null && frame.getLocation().getFileName() != null &&
|
||||||
frame.getLocation().getLine() >= 0 && debugInfo != null) {
|
frame.getLocation().getLine() >= 0 && debugInfo != null) {
|
||||||
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) {
|
if (enterMethod) {
|
||||||
for (MethodReference callMethod : callMethods) {
|
CallSiteSuccessorFinder successorFinder = new CallSiteSuccessorFinder(debugInfo, script,
|
||||||
for (MethodReference potentialMethod : debugInfo.getOverridingMethods(callMethod)) {
|
successors);
|
||||||
for (GeneratedLocation loc : debugInfo.getMethodEntrances(potentialMethod)) {
|
DebuggerCallSite[] callSites = debugInfo.getCallSites(frame.getLocation());
|
||||||
successors.add(new JavaScriptLocation(script, loc.getLine(), loc.getColumn()));
|
for (DebuggerCallSite callSite : callSites) {
|
||||||
}
|
callSite.acceptVisitor(successorFinder);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,6 +124,34 @@ public class Debugger {
|
||||||
javaScriptDebugger.resume();
|
javaScriptDebugger.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class CallSiteSuccessorFinder implements DebuggerCallSiteVisitor {
|
||||||
|
private DebugInformation debugInfo;
|
||||||
|
private String script;
|
||||||
|
Set<JavaScriptLocation> locations;
|
||||||
|
|
||||||
|
public CallSiteSuccessorFinder(DebugInformation debugInfo, String script, Set<JavaScriptLocation> locations) {
|
||||||
|
this.debugInfo = debugInfo;
|
||||||
|
this.script = script;
|
||||||
|
this.locations = locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(DebuggerVirtualCallSite callSite) {
|
||||||
|
for (MethodReference potentialMethod : debugInfo.getOverridingMethods(callSite.getMethod())) {
|
||||||
|
for (GeneratedLocation loc : debugInfo.getMethodEntrances(potentialMethod)) {
|
||||||
|
locations.add(new JavaScriptLocation(script, loc.getLine(), loc.getColumn()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(DebuggerStaticCallSite callSite) {
|
||||||
|
for (GeneratedLocation loc : debugInfo.getMethodEntrances(callSite.getMethod())) {
|
||||||
|
locations.add(new JavaScriptLocation(script, loc.getLine(), loc.getColumn()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean addFollowing(DebugInformation debugInfo, SourceLocation location, String script,
|
private boolean addFollowing(DebugInformation debugInfo, SourceLocation location, String script,
|
||||||
Set<SourceLocation> visited, Set<JavaScriptLocation> successors) {
|
Set<SourceLocation> visited, Set<JavaScriptLocation> successors) {
|
||||||
if (!visited.add(location)) {
|
if (!visited.add(location)) {
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -8,13 +23,9 @@ import org.teavm.model.MethodReference;
|
||||||
*/
|
*/
|
||||||
public class DebuggerVirtualCallSite extends DebuggerCallSite {
|
public class DebuggerVirtualCallSite extends DebuggerCallSite {
|
||||||
private MethodReference method;
|
private MethodReference method;
|
||||||
private int variableId;
|
|
||||||
private String variableName;
|
|
||||||
|
|
||||||
DebuggerVirtualCallSite(MethodReference method, int variableId, String variableName) {
|
DebuggerVirtualCallSite(MethodReference method) {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.variableId = variableId;
|
|
||||||
this.variableName = variableName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodReference getMethod() {
|
public MethodReference getMethod() {
|
||||||
|
@ -25,22 +36,6 @@ public class DebuggerVirtualCallSite extends DebuggerCallSite {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getVariableId() {
|
|
||||||
return variableId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVariableId(int variableId) {
|
|
||||||
this.variableId = variableId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVariableName() {
|
|
||||||
return variableName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVariableName(String variableName) {
|
|
||||||
this.variableName = variableName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acceptVisitor(DebuggerCallSiteVisitor visitor) {
|
public void acceptVisitor(DebuggerCallSiteVisitor visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
|
|
|
@ -22,5 +22,9 @@ import org.teavm.model.MethodReference;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public interface DeferredCallSite {
|
public interface DeferredCallSite {
|
||||||
void setMethod(MethodReference method);
|
void setVirtualMethod(MethodReference method);
|
||||||
|
|
||||||
|
void setStaticMethod(MethodReference method);
|
||||||
|
|
||||||
|
void clean();
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,15 +44,12 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter {
|
||||||
@Override
|
@Override
|
||||||
public DeferredCallSite emitCallSite() {
|
public DeferredCallSite emitCallSite() {
|
||||||
return new DeferredCallSite() {
|
return new DeferredCallSite() {
|
||||||
@Override public void setMethod(MethodReference method) {
|
@Override public void setVirtualMethod(MethodReference method) { }
|
||||||
}
|
@Override public void setStaticMethod(MethodReference method) { }
|
||||||
|
@Override public void clean() { }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void emitEmptyCallSite() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLocationProvider(LocationProvider locationProvider) {
|
public void setLocationProvider(LocationProvider locationProvider) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* 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.common.RecordArray;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class ExactMethodIterator {
|
||||||
|
private DebugInformation debugInformation;
|
||||||
|
private GeneratedLocation location;
|
||||||
|
private int classIndex;
|
||||||
|
private int methodIndex;
|
||||||
|
private int classId = -1;
|
||||||
|
private int methodId = -1;
|
||||||
|
private boolean endReached;
|
||||||
|
|
||||||
|
ExactMethodIterator(DebugInformation debugInformation) {
|
||||||
|
this.debugInformation = debugInformation;
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEndReached() {
|
||||||
|
return endReached;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void read() {
|
||||||
|
if (classIndex >= debugInformation.classMapping.size()) {
|
||||||
|
nextClassRecord();
|
||||||
|
} else if (methodIndex >= debugInformation.methodMapping.size()) {
|
||||||
|
nextMethodRecord();
|
||||||
|
} else if (classIndex < debugInformation.classMapping.size() &&
|
||||||
|
methodIndex < debugInformation.methodMapping.size()) {
|
||||||
|
RecordArray.Record classRecord = debugInformation.classMapping.get(classIndex++);
|
||||||
|
RecordArray.Record methodRecord = debugInformation.methodMapping.get(methodIndex++);
|
||||||
|
GeneratedLocation classLoc = DebugInformation.key(classRecord);
|
||||||
|
GeneratedLocation methodLoc = DebugInformation.key(methodRecord);
|
||||||
|
int cmp = classLoc.compareTo(methodLoc);
|
||||||
|
if (cmp < 0) {
|
||||||
|
nextClassRecord();
|
||||||
|
} else if (cmp > 0) {
|
||||||
|
nextMethodRecord();
|
||||||
|
} else {
|
||||||
|
nextClassRecord();
|
||||||
|
nextMethodRecord();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
endReached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nextClassRecord() {
|
||||||
|
RecordArray.Record record = debugInformation.classMapping.get(classIndex++);
|
||||||
|
classId = record.get(2);
|
||||||
|
location = DebugInformation.key(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nextMethodRecord() {
|
||||||
|
RecordArray.Record record = debugInformation.methodMapping.get(methodIndex++);
|
||||||
|
methodId = record.get(2);
|
||||||
|
location = DebugInformation.key(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClassNameId() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return classId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
int classId = getClassNameId();
|
||||||
|
return classId >= 0 ? debugInformation.getClassName(classId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMethodId() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return methodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodDescriptor getMethod() {
|
||||||
|
int methodId = getMethodId();
|
||||||
|
return methodId >= 0 ? debugInformation.getMethod(methodId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getExactMethodId() {
|
||||||
|
return debugInformation.getExactMethodId(classId, methodId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodReference getExactMethod() {
|
||||||
|
return new MethodReference(getClassName(), getMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneratedLocation getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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.MethodDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class MethodIterator {
|
||||||
|
private DebugInformation debugInformation;
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
MethodIterator(DebugInformation debugInformation) {
|
||||||
|
this.debugInformation = debugInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEndReached() {
|
||||||
|
return index < debugInformation.methodMapping.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneratedLocation getLocation() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return DebugInformation.key(debugInformation.methodMapping.get(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMethodId() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return debugInformation.methodMapping.get(index).get(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodDescriptor getMethod() {
|
||||||
|
int methodId = getMethodId();
|
||||||
|
return methodId >= 0 ? debugInformation.getMethod(methodId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
package org.teavm.debugging;
|
||||||
|
|
||||||
import org.teavm.common.RecordArray;
|
import org.teavm.common.RecordArray;
|
||||||
|
|
|
@ -27,9 +27,7 @@ class SourceMapsWriter {
|
||||||
private Writer output;
|
private Writer output;
|
||||||
private int lastLine;
|
private int lastLine;
|
||||||
private int lastColumn;
|
private int lastColumn;
|
||||||
private int sourceLine;
|
|
||||||
private int lastSourceLine;
|
private int lastSourceLine;
|
||||||
private int sourceFile;
|
|
||||||
private int lastSourceFile;
|
private int lastSourceFile;
|
||||||
private boolean first;
|
private boolean first;
|
||||||
|
|
||||||
|
@ -58,31 +56,10 @@ class SourceMapsWriter {
|
||||||
first = true;
|
first = true;
|
||||||
lastLine = 0;
|
lastLine = 0;
|
||||||
lastColumn = 0;
|
lastColumn = 0;
|
||||||
sourceLine = -1;
|
|
||||||
sourceFile = -1;
|
|
||||||
lastSourceFile = 0;
|
lastSourceFile = 0;
|
||||||
lastSourceLine = 0;
|
lastSourceLine = 0;
|
||||||
int i = 0;
|
for (SourceLocationIterator iter = debugInfo.iterateOverSourceLocations(); !iter.isEndReached(); iter.next()) {
|
||||||
int j = 0;
|
writeSegment(iter.getLocation(), iter.getFileNameId(), iter.getLine());
|
||||||
while (i < debugInfo.lineMapping.lines.length && j < debugInfo.fileMapping.lines.length) {
|
|
||||||
GeneratedLocation a = debugInfo.lineMapping.key(i);
|
|
||||||
GeneratedLocation b = debugInfo.fileMapping.key(j);
|
|
||||||
int cmp = a.compareTo(b);
|
|
||||||
if (cmp < 0) {
|
|
||||||
writeSegment(a, sourceFile, debugInfo.lineMapping.values[i++]);
|
|
||||||
} else if (cmp > 0) {
|
|
||||||
writeSegment(b, debugInfo.fileMapping.values[j++], sourceLine);
|
|
||||||
} else {
|
|
||||||
writeSegment(a, debugInfo.fileMapping.values[j++], debugInfo.lineMapping.values[i++] - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (i < debugInfo.lineMapping.lines.length) {
|
|
||||||
GeneratedLocation a = debugInfo.lineMapping.key(i);
|
|
||||||
writeSegment(a, sourceFile, debugInfo.lineMapping.values[i++]);
|
|
||||||
}
|
|
||||||
while (j < debugInfo.fileMapping.lines.length) {
|
|
||||||
GeneratedLocation b = debugInfo.fileMapping.key(j);
|
|
||||||
writeSegment(b, debugInfo.fileMapping.values[j++], sourceLine);
|
|
||||||
}
|
}
|
||||||
output.write("\"}");
|
output.write("\"}");
|
||||||
}
|
}
|
||||||
|
@ -106,8 +83,6 @@ class SourceMapsWriter {
|
||||||
lastSourceLine = sourceLine;
|
lastSourceLine = sourceLine;
|
||||||
}
|
}
|
||||||
lastColumn = loc.getColumn();
|
lastColumn = loc.getColumn();
|
||||||
this.sourceFile = sourceFile;
|
|
||||||
this.sourceLine = sourceLine;
|
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -608,7 +608,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
writer.ws().append("=").ws();
|
writer.ws().append("=").ws();
|
||||||
}
|
}
|
||||||
statement.getRightValue().acceptVisitor(this);
|
statement.getRightValue().acceptVisitor(this);
|
||||||
debugEmitter.emitEmptyCallSite();
|
debugEmitter.emitCallSite();
|
||||||
writer.append(";").softNewLine();
|
writer.append(";").softNewLine();
|
||||||
if (statement.getLocation() != null) {
|
if (statement.getLocation() != null) {
|
||||||
popLocation();
|
popLocation();
|
||||||
|
@ -640,7 +640,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
prevCallSite = debugEmitter.emitCallSite();
|
prevCallSite = debugEmitter.emitCallSite();
|
||||||
writer.append("if").ws().append("(");
|
writer.append("if").ws().append("(");
|
||||||
statement.getCondition().acceptVisitor(this);
|
statement.getCondition().acceptVisitor(this);
|
||||||
debugEmitter.emitEmptyCallSite();
|
debugEmitter.emitCallSite();
|
||||||
writer.append(")").ws().append("{").softNewLine().indent();
|
writer.append(")").ws().append("{").softNewLine().indent();
|
||||||
if (statement.getCondition().getLocation() != null) {
|
if (statement.getCondition().getLocation() != null) {
|
||||||
popLocation();
|
popLocation();
|
||||||
|
@ -678,7 +678,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
prevCallSite = debugEmitter.emitCallSite();
|
prevCallSite = debugEmitter.emitCallSite();
|
||||||
writer.append("switch").ws().append("(");
|
writer.append("switch").ws().append("(");
|
||||||
statement.getValue().acceptVisitor(this);
|
statement.getValue().acceptVisitor(this);
|
||||||
debugEmitter.emitEmptyCallSite();
|
debugEmitter.emitCallSite();
|
||||||
writer.append(")").ws().append("{").softNewLine().indent();
|
writer.append(")").ws().append("{").softNewLine().indent();
|
||||||
for (SwitchClause clause : statement.getClauses()) {
|
for (SwitchClause clause : statement.getClauses()) {
|
||||||
for (int condition : clause.getConditions()) {
|
for (int condition : clause.getConditions()) {
|
||||||
|
@ -713,7 +713,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
if (statement.getCondition() != null) {
|
if (statement.getCondition() != null) {
|
||||||
prevCallSite = debugEmitter.emitCallSite();
|
prevCallSite = debugEmitter.emitCallSite();
|
||||||
statement.getCondition().acceptVisitor(this);
|
statement.getCondition().acceptVisitor(this);
|
||||||
debugEmitter.emitEmptyCallSite();
|
debugEmitter.emitCallSite();
|
||||||
} else {
|
} else {
|
||||||
writer.append("true");
|
writer.append("true");
|
||||||
}
|
}
|
||||||
|
@ -794,7 +794,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
writer.append(' ');
|
writer.append(' ');
|
||||||
prevCallSite = debugEmitter.emitCallSite();
|
prevCallSite = debugEmitter.emitCallSite();
|
||||||
statement.getResult().acceptVisitor(this);
|
statement.getResult().acceptVisitor(this);
|
||||||
debugEmitter.emitEmptyCallSite();
|
debugEmitter.emitCallSite();
|
||||||
}
|
}
|
||||||
writer.append(";").softNewLine();
|
writer.append(";").softNewLine();
|
||||||
if (statement.getLocation() != null) {
|
if (statement.getLocation() != null) {
|
||||||
|
@ -815,7 +815,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
prevCallSite = debugEmitter.emitCallSite();
|
prevCallSite = debugEmitter.emitCallSite();
|
||||||
statement.getException().acceptVisitor(this);
|
statement.getException().acceptVisitor(this);
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
debugEmitter.emitEmptyCallSite();
|
debugEmitter.emitCallSite();
|
||||||
if (statement.getLocation() != null) {
|
if (statement.getLocation() != null) {
|
||||||
popLocation();
|
popLocation();
|
||||||
}
|
}
|
||||||
|
@ -1317,6 +1317,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
if (lastCallSite == null) {
|
if (lastCallSite == null) {
|
||||||
lastCallSite = callSite;
|
lastCallSite = callSite;
|
||||||
}
|
}
|
||||||
|
boolean virtual = false;
|
||||||
switch (expr.getType()) {
|
switch (expr.getType()) {
|
||||||
case STATIC:
|
case STATIC:
|
||||||
writer.append(fullName).append("(");
|
writer.append(fullName).append("(");
|
||||||
|
@ -1350,6 +1351,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
expr.getArguments().get(i).acceptVisitor(this);
|
expr.getArguments().get(i).acceptVisitor(this);
|
||||||
}
|
}
|
||||||
writer.append(')');
|
writer.append(')');
|
||||||
|
virtual = true;
|
||||||
break;
|
break;
|
||||||
case CONSTRUCTOR:
|
case CONSTRUCTOR:
|
||||||
writer.append(className).append(".").append(name).append("(");
|
writer.append(className).append(".").append(name).append("(");
|
||||||
|
@ -1364,7 +1366,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (lastCallSite != null) {
|
if (lastCallSite != null) {
|
||||||
lastCallSite.setMethod(expr.getMethod());
|
if (virtual) {
|
||||||
|
lastCallSite.setVirtualMethod(expr.getMethod());
|
||||||
|
} else {
|
||||||
|
lastCallSite.setStaticMethod(expr.getMethod());
|
||||||
|
}
|
||||||
lastCallSite = callSite;
|
lastCallSite = callSite;
|
||||||
}
|
}
|
||||||
if (shouldEraseCallSite) {
|
if (shouldEraseCallSite) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user