mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-03 05:44:10 -08:00
JS: preserve stack trace items when agressive inlining enabled
This commit is contained in:
parent
abf90e8b5f
commit
4ef231c7fa
|
@ -497,6 +497,7 @@ class StatementGenerator implements InstructionVisitor {
|
||||||
} else {
|
} else {
|
||||||
stmt = Statement.assign(null, invocationExpr);
|
stmt = Statement.assign(null, invocationExpr);
|
||||||
}
|
}
|
||||||
|
invocationExpr.setLocation(currentLocation);
|
||||||
stmt.setLocation(currentLocation);
|
stmt.setLocation(currentLocation);
|
||||||
stmt.setAsync(async);
|
stmt.setAsync(async);
|
||||||
async = false;
|
async = false;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Deque;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import org.teavm.backend.javascript.codegen.NamingStrategy;
|
import org.teavm.backend.javascript.codegen.NamingStrategy;
|
||||||
|
@ -38,6 +39,7 @@ import org.teavm.interop.PlatformMarker;
|
||||||
import org.teavm.model.AnnotationReader;
|
import org.teavm.model.AnnotationReader;
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.InliningInfo;
|
||||||
import org.teavm.model.ListableClassReaderSource;
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -62,6 +64,7 @@ public class RenderingContext {
|
||||||
private final Map<MethodReference, InjectorHolder> injectorMap = new HashMap<>();
|
private final Map<MethodReference, InjectorHolder> injectorMap = new HashMap<>();
|
||||||
private boolean minifying;
|
private boolean minifying;
|
||||||
private ClassInitializerInfo classInitializerInfo;
|
private ClassInitializerInfo classInitializerInfo;
|
||||||
|
private TextLocation lastEmittedLocation = TextLocation.EMPTY;
|
||||||
|
|
||||||
public RenderingContext(DebugInformationEmitter debugEmitter,
|
public RenderingContext(DebugInformationEmitter debugEmitter,
|
||||||
ClassReaderSource initialClassSource, ListableClassReaderSource classSource,
|
ClassReaderSource initialClassSource, ListableClassReaderSource classSource,
|
||||||
|
@ -128,11 +131,11 @@ public class RenderingContext {
|
||||||
LocationStackEntry prevEntry = locationStack.peek();
|
LocationStackEntry prevEntry = locationStack.peek();
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
if (prevEntry == null || !location.equals(prevEntry.location)) {
|
if (prevEntry == null || !location.equals(prevEntry.location)) {
|
||||||
debugEmitter.emitLocation(location.getFileName(), location.getLine());
|
emitLocation(location);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prevEntry != null) {
|
if (prevEntry != null) {
|
||||||
debugEmitter.emitLocation(null, -1);
|
emitLocation(TextLocation.EMPTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
locationStack.push(new LocationStackEntry(location));
|
locationStack.push(new LocationStackEntry(location));
|
||||||
|
@ -143,13 +146,64 @@ public class RenderingContext {
|
||||||
LocationStackEntry entry = locationStack.peek();
|
LocationStackEntry entry = locationStack.peek();
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
if (!entry.location.equals(prevEntry.location)) {
|
if (!entry.location.equals(prevEntry.location)) {
|
||||||
debugEmitter.emitLocation(entry.location.getFileName(), entry.location.getLine());
|
emitLocation(entry.location);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debugEmitter.emitLocation(null, -1);
|
emitLocation(TextLocation.EMPTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void emitLocation(TextLocation location) {
|
||||||
|
if (lastEmittedLocation.equals(location)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileName = lastEmittedLocation.getFileName();
|
||||||
|
int lineNumber = lastEmittedLocation.getLine();
|
||||||
|
if (lastEmittedLocation.getInlining() != location.getInlining()) {
|
||||||
|
InliningInfo[] newPath = location.getInliningPath();
|
||||||
|
InliningInfo[] prevPath = lastEmittedLocation.getInliningPath();
|
||||||
|
|
||||||
|
InliningInfo lastCommonInlining = null;
|
||||||
|
int pathIndex = 0;
|
||||||
|
while (pathIndex < prevPath.length && pathIndex < newPath.length
|
||||||
|
&& prevPath[pathIndex].equals(newPath[pathIndex])) {
|
||||||
|
lastCommonInlining = prevPath[pathIndex++];
|
||||||
|
}
|
||||||
|
|
||||||
|
InliningInfo prevInlining = lastEmittedLocation.getInlining();
|
||||||
|
while (prevInlining != lastCommonInlining) {
|
||||||
|
debugEmitter.exitLocation();
|
||||||
|
fileName = prevInlining.getFileName();
|
||||||
|
lineNumber = prevInlining.getLine();
|
||||||
|
prevInlining = prevInlining.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pathIndex < newPath.length) {
|
||||||
|
InliningInfo inlining = newPath[pathIndex++];
|
||||||
|
emitSimpleLocation(fileName, lineNumber, inlining.getFileName(), inlining.getLine());
|
||||||
|
fileName = null;
|
||||||
|
lineNumber = -1;
|
||||||
|
|
||||||
|
debugEmitter.enterLocation();
|
||||||
|
debugEmitter.emitClass(inlining.getMethod().getClassName());
|
||||||
|
debugEmitter.emitMethod(inlining.getMethod().getDescriptor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitSimpleLocation(fileName, lineNumber, location.getFileName(), location.getLine());
|
||||||
|
lastEmittedLocation = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void emitSimpleLocation(String fileName, int lineNumber, String newFileName, int newLineNumber) {
|
||||||
|
if (Objects.equals(fileName, newFileName) && lineNumber == newLineNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugEmitter.emitLocation(newFileName, newLineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isMinifying() {
|
public boolean isMinifying() {
|
||||||
return minifying;
|
return minifying;
|
||||||
}
|
}
|
||||||
|
|
66
core/src/main/java/org/teavm/cache/AstIO.java
vendored
66
core/src/main/java/org/teavm/cache/AstIO.java
vendored
|
@ -250,6 +250,10 @@ public class AstIO {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String fileName = lastLocation.getFileName();
|
||||||
|
int lineNumber = lastLocation.getLine();
|
||||||
|
|
||||||
|
if (location.getInlining() != lastLocation.getInlining()) {
|
||||||
InliningInfo lastCommonInlining = null;
|
InliningInfo lastCommonInlining = null;
|
||||||
InliningInfo[] prevPath = lastLocation.getInliningPath();
|
InliningInfo[] prevPath = lastLocation.getInliningPath();
|
||||||
InliningInfo[] newPath = location.getInliningPath();
|
InliningInfo[] newPath = location.getInliningPath();
|
||||||
|
@ -259,38 +263,50 @@ public class AstIO {
|
||||||
lastCommonInlining = prevPath[pathIndex++];
|
lastCommonInlining = prevPath[pathIndex++];
|
||||||
}
|
}
|
||||||
|
|
||||||
InliningInfo prevInlining = lastLocation.getInlining();
|
InliningInfo prevInlining = location.getInlining();
|
||||||
while (prevInlining != lastCommonInlining) {
|
while (prevInlining != lastCommonInlining) {
|
||||||
output.writeUnsigned(124);
|
output.writeUnsigned(123);
|
||||||
|
fileName = prevInlining.getFileName();
|
||||||
|
lineNumber = prevInlining.getLine();
|
||||||
prevInlining = prevInlining.getParent();
|
prevInlining = prevInlining.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (pathIndex < newPath.length) {
|
while (pathIndex < newPath.length) {
|
||||||
InliningInfo inlining = newPath[pathIndex++];
|
InliningInfo inlining = newPath[pathIndex++];
|
||||||
|
writeSimpleLocation(fileName, lineNumber, inlining.getFileName(), inlining.getLine());
|
||||||
|
fileName = null;
|
||||||
|
lineNumber = -1;
|
||||||
|
|
||||||
|
output.writeUnsigned(124);
|
||||||
MethodReference method = inlining.getMethod();
|
MethodReference method = inlining.getMethod();
|
||||||
output.writeUnsigned(inlining.isEmpty() ? 122 : 123);
|
|
||||||
output.writeUnsigned(symbolTable.lookup(method.getClassName()));
|
output.writeUnsigned(symbolTable.lookup(method.getClassName()));
|
||||||
output.writeUnsigned(symbolTable.lookup(method.getDescriptor().toString()));
|
output.writeUnsigned(symbolTable.lookup(method.getDescriptor().toString()));
|
||||||
if (!inlining.isEmpty()) {
|
|
||||||
output.writeUnsigned(fileTable.lookup(inlining.getFileName()));
|
|
||||||
output.writeUnsigned(inlining.getLine());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location.isEmpty()) {
|
writeSimpleLocation(fileName, lineNumber, location.getFileName(), location.getLine());
|
||||||
output.writeUnsigned(127);
|
|
||||||
} else if (!lastLocation.isEmpty() && lastLocation.getFileName().equals(location.getFileName())) {
|
|
||||||
output.writeUnsigned(126);
|
|
||||||
output.writeSigned(location.getLine() - lastLocation.getLine());
|
|
||||||
} else {
|
|
||||||
output.writeUnsigned(125);
|
|
||||||
output.writeUnsigned(fileTable.lookup(location.getFileName()));
|
|
||||||
output.writeUnsigned(location.getLine());
|
|
||||||
}
|
|
||||||
|
|
||||||
lastLocation = location;
|
lastLocation = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeSimpleLocation(String fileName, int lineNumber, String newFileName, int newLineNumber)
|
||||||
|
throws IOException {
|
||||||
|
if (Objects.equals(fileName, newFileName) && lineNumber == newLineNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newFileName == null) {
|
||||||
|
output.writeUnsigned(127);
|
||||||
|
} else if (fileName != null && fileName.equals(newFileName)) {
|
||||||
|
output.writeUnsigned(126);
|
||||||
|
output.writeSigned(newLineNumber - lineNumber);
|
||||||
|
} else {
|
||||||
|
output.writeUnsigned(125);
|
||||||
|
output.writeUnsigned(fileTable.lookup(newFileName));
|
||||||
|
output.writeUnsigned(newLineNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void writeSequence(List<Statement> sequence) throws IOException {
|
private void writeSequence(List<Statement> sequence) throws IOException {
|
||||||
output.writeUnsigned(sequence.size());
|
output.writeUnsigned(sequence.size());
|
||||||
for (Statement part : sequence) {
|
for (Statement part : sequence) {
|
||||||
|
@ -741,25 +757,17 @@ public class AstIO {
|
||||||
lastReadLocation = new TextLocation(fileTable.at(input.readUnsigned()), input.readUnsigned(),
|
lastReadLocation = new TextLocation(fileTable.at(input.readUnsigned()), input.readUnsigned(),
|
||||||
lastReadInlining);
|
lastReadInlining);
|
||||||
break;
|
break;
|
||||||
case 122:
|
case 124: {
|
||||||
case 123: {
|
|
||||||
String className = symbolTable.at(input.readUnsigned());
|
String className = symbolTable.at(input.readUnsigned());
|
||||||
MethodDescriptor methodDescriptor = MethodDescriptor.parse(symbolTable.at(input.readUnsigned()));
|
MethodDescriptor methodDescriptor = MethodDescriptor.parse(symbolTable.at(input.readUnsigned()));
|
||||||
methodDescriptor = referenceCache.getCached(methodDescriptor);
|
methodDescriptor = referenceCache.getCached(methodDescriptor);
|
||||||
String fileName;
|
|
||||||
int lineNumber;
|
|
||||||
if (type == 122) {
|
|
||||||
fileName = fileTable.at(input.readUnsigned());
|
|
||||||
lineNumber = input.readUnsigned();
|
|
||||||
} else {
|
|
||||||
fileName = null;
|
|
||||||
lineNumber = -1;
|
|
||||||
}
|
|
||||||
lastReadInlining = new InliningInfo(referenceCache.getCached(className, methodDescriptor),
|
lastReadInlining = new InliningInfo(referenceCache.getCached(className, methodDescriptor),
|
||||||
fileName, lineNumber, lastReadInlining);
|
lastReadLocation.getFileName(), lastReadLocation.getLine(), lastReadInlining);
|
||||||
|
lastReadLocation = new TextLocation(null, -1, lastReadInlining);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 124:
|
case 123:
|
||||||
|
lastReadLocation = new TextLocation(lastReadInlining.getFileName(), lastReadInlining.getLine());
|
||||||
lastReadInlining = lastReadInlining.getParent();
|
lastReadInlining = lastReadInlining.getParent();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import org.teavm.model.BasicBlock;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.BasicBlockReader;
|
import org.teavm.model.BasicBlockReader;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
|
@ -208,7 +209,7 @@ public class ProgramIO {
|
||||||
}
|
}
|
||||||
|
|
||||||
InliningInfo inliningInfo = null;
|
InliningInfo inliningInfo = null;
|
||||||
TextLocation location = null;
|
TextLocation location = TextLocation.EMPTY;
|
||||||
insnLoop: while (true) {
|
insnLoop: while (true) {
|
||||||
int insnType = data.readUnsigned();
|
int insnType = data.readUnsigned();
|
||||||
switch (insnType) {
|
switch (insnType) {
|
||||||
|
@ -228,24 +229,16 @@ public class ProgramIO {
|
||||||
location = new TextLocation(location.getFileName(), line, inliningInfo);
|
location = new TextLocation(location.getFileName(), line, inliningInfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 124:
|
|
||||||
case 125: {
|
case 125: {
|
||||||
String className = symbolTable.at(data.readUnsigned());
|
String className = symbolTable.at(data.readUnsigned());
|
||||||
MethodDescriptor methodDescriptor = parseMethodDescriptor(symbolTable.at(data.readUnsigned()));
|
MethodDescriptor methodDescriptor = parseMethodDescriptor(symbolTable.at(data.readUnsigned()));
|
||||||
String fileName;
|
|
||||||
int lineNumber;
|
|
||||||
if (insnType == 125) {
|
|
||||||
fileName = fileTable.at(data.readUnsigned());
|
|
||||||
lineNumber = data.readUnsigned();
|
|
||||||
} else {
|
|
||||||
fileName = null;
|
|
||||||
lineNumber = -1;
|
|
||||||
}
|
|
||||||
inliningInfo = new InliningInfo(createMethodReference(className, methodDescriptor),
|
inliningInfo = new InliningInfo(createMethodReference(className, methodDescriptor),
|
||||||
fileName, lineNumber, inliningInfo);
|
location.getFileName(), location.getLine(), inliningInfo);
|
||||||
|
location = new TextLocation(null, -1, inliningInfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 126:
|
case 126:
|
||||||
|
location = new TextLocation(inliningInfo.getFileName(), inliningInfo.getLine());
|
||||||
inliningInfo = inliningInfo.getParent();
|
inliningInfo = inliningInfo.getParent();
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
|
@ -276,6 +269,10 @@ public class ProgramIO {
|
||||||
newLocation = TextLocation.EMPTY;
|
newLocation = TextLocation.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String fileName = location.getFileName();
|
||||||
|
int lineNumber = location.getLine();
|
||||||
|
|
||||||
|
if (newLocation.getInlining() != location.getInlining()) {
|
||||||
InliningInfo lastCommonInlining = null;
|
InliningInfo lastCommonInlining = null;
|
||||||
InliningInfo[] prevPath = location.getInliningPath();
|
InliningInfo[] prevPath = location.getInliningPath();
|
||||||
InliningInfo[] newPath = newLocation.getInliningPath();
|
InliningInfo[] newPath = newLocation.getInliningPath();
|
||||||
|
@ -288,39 +285,49 @@ public class ProgramIO {
|
||||||
InliningInfo prevInlining = location.getInlining();
|
InliningInfo prevInlining = location.getInlining();
|
||||||
while (prevInlining != lastCommonInlining) {
|
while (prevInlining != lastCommonInlining) {
|
||||||
output.writeUnsigned(126);
|
output.writeUnsigned(126);
|
||||||
|
fileName = prevInlining.getFileName();
|
||||||
|
lineNumber = prevInlining.getLine();
|
||||||
prevInlining = prevInlining.getParent();
|
prevInlining = prevInlining.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (pathIndex < newPath.length) {
|
while (pathIndex < newPath.length) {
|
||||||
InliningInfo inlining = newPath[pathIndex++];
|
InliningInfo inlining = newPath[pathIndex++];
|
||||||
|
writeSimpleLocation(fileName, lineNumber, inlining.getFileName(), inlining.getLine());
|
||||||
|
fileName = null;
|
||||||
|
lineNumber = -1;
|
||||||
|
|
||||||
|
output.writeUnsigned(125);
|
||||||
MethodReference method = inlining.getMethod();
|
MethodReference method = inlining.getMethod();
|
||||||
output.writeUnsigned(inlining.isEmpty() ? 124 : 125);
|
|
||||||
output.writeUnsigned(symbolTable.lookup(method.getClassName()));
|
output.writeUnsigned(symbolTable.lookup(method.getClassName()));
|
||||||
output.writeUnsigned(symbolTable.lookup(method.getDescriptor().toString()));
|
output.writeUnsigned(symbolTable.lookup(method.getDescriptor().toString()));
|
||||||
if (!inlining.isEmpty()) {
|
|
||||||
output.writeUnsigned(fileTable.lookup(inlining.getFileName()));
|
|
||||||
output.writeUnsigned(inlining.getLine());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newLocation.isEmpty()) {
|
writeSimpleLocation(fileName, lineNumber, newLocation.getFileName(), newLocation.getLine());
|
||||||
output.writeUnsigned(1);
|
|
||||||
} else {
|
|
||||||
if (!location.isEmpty() && location.getFileName().equals(newLocation.getFileName())) {
|
|
||||||
output.writeUnsigned(127);
|
|
||||||
output.writeSigned(newLocation.getLine() - location.getLine());
|
|
||||||
} else {
|
|
||||||
output.writeUnsigned(2);
|
|
||||||
output.writeUnsigned(fileTable.lookup(newLocation.getFileName()));
|
|
||||||
output.writeUnsigned(newLocation.getLine());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
location = newLocation;
|
location = newLocation;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IOExceptionWrapper(e);
|
throw new IOExceptionWrapper(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeSimpleLocation(String fileName, int lineNumber, String newFileName, int newLineNumber)
|
||||||
|
throws IOException {
|
||||||
|
if (Objects.equals(fileName, newFileName) && lineNumber == newLineNumber) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newFileName == null) {
|
||||||
|
output.writeUnsigned(1);
|
||||||
|
} else if (fileName != null && fileName.equals(newFileName)) {
|
||||||
|
output.writeUnsigned(127);
|
||||||
|
output.writeSigned(newLineNumber - lineNumber);
|
||||||
|
} else {
|
||||||
|
output.writeUnsigned(2);
|
||||||
|
output.writeUnsigned(fileTable.lookup(newFileName));
|
||||||
|
output.writeUnsigned(newLineNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void nop() {
|
public void nop() {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.information;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -38,10 +38,7 @@ public class DebugInformation {
|
||||||
long[] exactMethods;
|
long[] exactMethods;
|
||||||
Map<Long, Integer> exactMethodMap;
|
Map<Long, Integer> exactMethodMap;
|
||||||
RecordArray[] fileDescriptions;
|
RecordArray[] fileDescriptions;
|
||||||
RecordArray fileMapping;
|
Layer[] layers;
|
||||||
RecordArray classMapping;
|
|
||||||
RecordArray methodMapping;
|
|
||||||
RecordArray lineMapping;
|
|
||||||
RecordArray callSiteMapping;
|
RecordArray callSiteMapping;
|
||||||
RecordArray statementStartMapping;
|
RecordArray statementStartMapping;
|
||||||
RecordArray[] variableMappings;
|
RecordArray[] variableMappings;
|
||||||
|
@ -69,14 +66,6 @@ public class DebugInformation {
|
||||||
return variableNames.clone();
|
return variableNames.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LineNumberIterator iterateOverLineNumbers() {
|
|
||||||
return new LineNumberIterator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileNameIterator iterateOverFileNames() {
|
|
||||||
return new FileNameIterator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFileName(int fileNameId) {
|
public String getFileName(int fileNameId) {
|
||||||
return fileNames[fileNameId];
|
return fileNames[fileNameId];
|
||||||
}
|
}
|
||||||
|
@ -135,16 +124,12 @@ public class DebugInformation {
|
||||||
return id != null ? id : -1;
|
return id != null ? id : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassNameIterator iterateOverClassNames() {
|
public int layerCount() {
|
||||||
return new ClassNameIterator(this);
|
return layers.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodIterator iterateOverMethods() {
|
public ExactMethodIterator iterateOverExactMethods(int layerIndex) {
|
||||||
return new MethodIterator(this);
|
return new ExactMethodIterator(this, layers[layerIndex]);
|
||||||
}
|
|
||||||
|
|
||||||
public ExactMethodIterator iterateOverExactMethods() {
|
|
||||||
return new ExactMethodIterator(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) {
|
public Collection<GeneratedLocation> getGeneratedLocations(String fileName, int line) {
|
||||||
|
@ -177,29 +162,67 @@ public class DebugInformation {
|
||||||
return new SourceLocationIterator(this);
|
return new SourceLocationIterator(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LayerSourceLocationIterator iterateOverSourceLocations(int layer) {
|
||||||
|
return new LayerSourceLocationIterator(this, layers[layer]);
|
||||||
|
}
|
||||||
|
|
||||||
public SourceLocation getSourceLocation(int line, int column) {
|
public SourceLocation getSourceLocation(int line, int column) {
|
||||||
return getSourceLocation(new GeneratedLocation(line, column));
|
return getSourceLocation(new GeneratedLocation(line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SourceLocation getSourceLocation(int line, int column, int layerIndex) {
|
||||||
|
return getSourceLocation(new GeneratedLocation(line, column), layerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public SourceLocation getSourceLocation(GeneratedLocation generatedLocation) {
|
public SourceLocation getSourceLocation(GeneratedLocation generatedLocation) {
|
||||||
String fileName = componentByKey(fileMapping, fileNames, generatedLocation);
|
return getSourceLocation(generatedLocation, autodetectLayer(generatedLocation));
|
||||||
int lineNumberIndex = indexByKey(lineMapping, generatedLocation);
|
}
|
||||||
int lineNumber = lineNumberIndex >= 0 ? lineMapping.get(lineNumberIndex).get(2) : -1;
|
|
||||||
|
public SourceLocation getSourceLocation(GeneratedLocation generatedLocation, int layerIndex) {
|
||||||
|
if (layerIndex < 0 || layerIndex >= layers.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer layer = layers[layerIndex];
|
||||||
|
String fileName = componentByKey(layer.fileMapping, fileNames, generatedLocation);
|
||||||
|
int lineNumberIndex = indexByKey(layer.lineMapping, generatedLocation);
|
||||||
|
int lineNumber = lineNumberIndex >= 0 ? layer.lineMapping.get(lineNumberIndex).get(2) : -1;
|
||||||
return new SourceLocation(fileName, lineNumber);
|
return new SourceLocation(fileName, lineNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodReference getMethodAt(GeneratedLocation generatedLocation) {
|
public MethodReference getMethodAt(GeneratedLocation generatedLocation) {
|
||||||
String className = componentByKey(classMapping, classNames, generatedLocation);
|
return getMethodAt(generatedLocation, autodetectLayer(generatedLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodReference getMethodAt(GeneratedLocation generatedLocation, int layerIndex) {
|
||||||
|
if (layerIndex < 0 || layerIndex >= layers.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer layer = layers[layerIndex];
|
||||||
|
|
||||||
|
String className = componentByKey(layer.classMapping, classNames, generatedLocation);
|
||||||
if (className == null) {
|
if (className == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String method = componentByKey(methodMapping, methods, generatedLocation);
|
String method = componentByKey(layer.methodMapping, methods, generatedLocation);
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return referenceCache.getCached(className, referenceCache.parseDescriptorCached(method));
|
return referenceCache.getCached(className, referenceCache.parseDescriptorCached(method));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int autodetectLayer(GeneratedLocation generatedLocation) {
|
||||||
|
int layerIndex = 0;
|
||||||
|
for (int i = 1; i < layers.length; ++i) {
|
||||||
|
if (componentByKey(layers[i].classMapping, classNames, generatedLocation) == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
layerIndex = i;
|
||||||
|
}
|
||||||
|
return layerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
public MethodReference getMethodAt(int line, int column) {
|
public MethodReference getMethodAt(int line, int column) {
|
||||||
return getMethodAt(new GeneratedLocation(line, column));
|
return getMethodAt(new GeneratedLocation(line, column));
|
||||||
}
|
}
|
||||||
|
@ -460,7 +483,9 @@ public class DebugInformation {
|
||||||
for (int i = 0; i < builders.length; ++i) {
|
for (int i = 0; i < builders.length; ++i) {
|
||||||
builders[i] = new RecordArrayBuilder(0, 1);
|
builders[i] = new RecordArrayBuilder(0, 1);
|
||||||
}
|
}
|
||||||
for (SourceLocationIterator iter = iterateOverSourceLocations(); !iter.isEndReached(); iter.next()) {
|
for (int layer = 0; layer < layers.length; ++layer) {
|
||||||
|
for (LayerSourceLocationIterator iter = iterateOverSourceLocations(layer);
|
||||||
|
!iter.isEndReached(); iter.next()) {
|
||||||
if (iter.getFileNameId() >= 0 && iter.getLine() >= 0) {
|
if (iter.getFileNameId() >= 0 && iter.getLine() >= 0) {
|
||||||
RecordArrayBuilder builder = builders[iter.getFileNameId()];
|
RecordArrayBuilder builder = builders[iter.getFileNameId()];
|
||||||
while (builder.size() <= iter.getLine()) {
|
while (builder.size() <= iter.getLine()) {
|
||||||
|
@ -472,6 +497,7 @@ public class DebugInformation {
|
||||||
array.add(loc.getColumn());
|
array.add(loc.getColumn());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fileDescriptions = new RecordArray[builders.length];
|
fileDescriptions = new RecordArray[builders.length];
|
||||||
for (int i = 0; i < fileDescriptions.length; ++i) {
|
for (int i = 0; i < fileDescriptions.length; ++i) {
|
||||||
fileDescriptions[i] = builders[i].build();
|
fileDescriptions[i] = builders[i].build();
|
||||||
|
@ -486,7 +512,8 @@ public class DebugInformation {
|
||||||
GeneratedLocation prevLocation = new GeneratedLocation(0, 0);
|
GeneratedLocation prevLocation = new GeneratedLocation(0, 0);
|
||||||
MethodReference prevMethod = null;
|
MethodReference prevMethod = null;
|
||||||
int prevMethodId = -1;
|
int prevMethodId = -1;
|
||||||
for (ExactMethodIterator iter = iterateOverExactMethods(); !iter.isEndReached(); iter.next()) {
|
RecordArray lineMapping = layers[0].lineMapping;
|
||||||
|
for (ExactMethodIterator iter = iterateOverExactMethods(0); !iter.isEndReached(); iter.next()) {
|
||||||
int id = iter.getExactMethodId();
|
int id = iter.getExactMethodId();
|
||||||
if (prevMethod != null) {
|
if (prevMethod != null) {
|
||||||
int lineIndex = Math.max(0, indexByKey(lineMapping, prevLocation));
|
int lineIndex = Math.max(0, indexByKey(lineMapping, prevLocation));
|
||||||
|
@ -596,8 +623,9 @@ public class DebugInformation {
|
||||||
GeneratedLocation loc = key(callSiteRec);
|
GeneratedLocation loc = key(callSiteRec);
|
||||||
int callSiteType = callSiteRec.get(2);
|
int callSiteType = callSiteRec.get(2);
|
||||||
if (callSiteType != DebuggerCallSite.NONE) {
|
if (callSiteType != DebuggerCallSite.NONE) {
|
||||||
int line = valueByKey(lineMapping, loc);
|
int layerIndex = autodetectLayer(loc);
|
||||||
int fileId = valueByKey(fileMapping, loc);
|
int line = valueByKey(layers[layerIndex].lineMapping, loc);
|
||||||
|
int fileId = valueByKey(layers[layerIndex].fileMapping, loc);
|
||||||
if (fileId >= 0 && line >= 0) {
|
if (fileId >= 0 && line >= 0) {
|
||||||
RecordArrayBuilder builder = builders[fileId];
|
RecordArrayBuilder builder = builders[fileId];
|
||||||
while (builder.size() <= line) {
|
while (builder.size() <= line) {
|
||||||
|
@ -699,4 +727,11 @@ public class DebugInformation {
|
||||||
return references;
|
return references;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class Layer {
|
||||||
|
RecordArray fileMapping;
|
||||||
|
RecordArray classMapping;
|
||||||
|
RecordArray methodMapping;
|
||||||
|
RecordArray lineMapping;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,23 +34,20 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
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 RecordArrayBuilder statementStartMapping = new RecordArrayBuilder(2, 0);
|
private RecordArrayBuilder statementStartMapping = new RecordArrayBuilder(2, 0);
|
||||||
private RecordArrayBuilder fileMapping = new RecordArrayBuilder(3, 0);
|
private List<LayerBuilder> layers = new ArrayList<>();
|
||||||
private RecordArrayBuilder lineMapping = new RecordArrayBuilder(3, 0);
|
private LayerBuilder currentLayer;
|
||||||
private RecordArrayBuilder classMapping = new RecordArrayBuilder(3, 0);
|
private int currentLayerIndex;
|
||||||
private RecordArrayBuilder methodMapping = new RecordArrayBuilder(3, 0);
|
|
||||||
private RecordArrayBuilder callSiteMapping = new RecordArrayBuilder(4, 0);
|
private RecordArrayBuilder callSiteMapping = new RecordArrayBuilder(4, 0);
|
||||||
private Map<Integer, RecordArrayBuilder> variableMappings = new HashMap<>();
|
private Map<Integer, RecordArrayBuilder> variableMappings = new HashMap<>();
|
||||||
private MethodDescriptor currentMethod;
|
|
||||||
private String currentClass;
|
|
||||||
private String currentFileName;
|
|
||||||
private int currentClassMetadata = -1;
|
private int currentClassMetadata = -1;
|
||||||
private List<ClassMetadata> classesMetadata = new ArrayList<>();
|
private List<ClassMetadata> classesMetadata = new ArrayList<>();
|
||||||
private List<RecordArrayBuilder> cfgs = new ArrayList<>();
|
private List<RecordArrayBuilder> cfgs = new ArrayList<>();
|
||||||
private int currentLine;
|
|
||||||
private ReferenceCache referenceCache;
|
private ReferenceCache referenceCache;
|
||||||
|
|
||||||
public DebugInformationBuilder(ReferenceCache referenceCache) {
|
public DebugInformationBuilder(ReferenceCache referenceCache) {
|
||||||
this.referenceCache = referenceCache;
|
this.referenceCache = referenceCache;
|
||||||
|
currentLayer = new LayerBuilder();
|
||||||
|
layers.add(currentLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocationProvider getLocationProvider() {
|
public LocationProvider getLocationProvider() {
|
||||||
|
@ -66,16 +63,32 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
public void emitLocation(String fileName, int line) {
|
public void emitLocation(String fileName, int line) {
|
||||||
debugInformation = null;
|
debugInformation = null;
|
||||||
int fileIndex = files.index(fileName);
|
int fileIndex = files.index(fileName);
|
||||||
if (!Objects.equals(currentFileName, fileName)) {
|
if (!Objects.equals(currentLayer.currentFileName, fileName)) {
|
||||||
add(fileMapping, fileIndex);
|
add(currentLayer.fileMapping, fileIndex);
|
||||||
currentFileName = fileName;
|
currentLayer.currentFileName = fileName;
|
||||||
}
|
}
|
||||||
if (currentLine != line) {
|
if (currentLayer.currentLine != line) {
|
||||||
add(lineMapping, line);
|
add(currentLayer.lineMapping, line);
|
||||||
currentLine = line;
|
currentLayer.currentLine = line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enterLocation() {
|
||||||
|
if (++currentLayerIndex >= layers.size()) {
|
||||||
|
layers.add(new LayerBuilder());
|
||||||
|
}
|
||||||
|
currentLayer = layers.get(currentLayerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exitLocation() {
|
||||||
|
emitClass(null);
|
||||||
|
emitMethod(null);
|
||||||
|
emitLocation(null, -1);
|
||||||
|
currentLayer = layers.get(--currentLayerIndex);
|
||||||
|
}
|
||||||
|
|
||||||
private RecordArrayBuilder.Record add(RecordArrayBuilder builder) {
|
private RecordArrayBuilder.Record add(RecordArrayBuilder builder) {
|
||||||
if (builder.size() > 1) {
|
if (builder.size() > 1) {
|
||||||
RecordArrayBuilder.Record lastRecord = builder.get(builder.size() - 1);
|
RecordArrayBuilder.Record lastRecord = builder.get(builder.size() - 1);
|
||||||
|
@ -99,9 +112,9 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
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, currentLayer.currentClass)) {
|
||||||
add(classMapping, classIndex);
|
add(currentLayer.classMapping, classIndex);
|
||||||
currentClass = className;
|
currentLayer.currentClass = className;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,12 +122,12 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
public void emitMethod(MethodDescriptor method) {
|
public void emitMethod(MethodDescriptor method) {
|
||||||
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, currentLayer.currentMethod)) {
|
||||||
add(methodMapping, methodIndex);
|
add(currentLayer.methodMapping, methodIndex);
|
||||||
currentMethod = method;
|
currentLayer.currentMethod = method;
|
||||||
}
|
}
|
||||||
if (currentClass != null) {
|
if (currentLayer.currentClass != null) {
|
||||||
int classIndex = classes.index(currentClass);
|
int classIndex = classes.index(currentLayer.currentClass);
|
||||||
long fullIndex = ((long) classIndex << 32) | methodIndex;
|
long fullIndex = ((long) classIndex << 32) | methodIndex;
|
||||||
if (!exactMethodMap.containsKey(fullIndex)) {
|
if (!exactMethodMap.containsKey(fullIndex)) {
|
||||||
exactMethodMap.put(fullIndex, exactMethods.size());
|
exactMethodMap.put(fullIndex, exactMethods.size());
|
||||||
|
@ -283,10 +296,19 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
debugInformation.exactMethodMap = new HashMap<>(exactMethodMap);
|
debugInformation.exactMethodMap = new HashMap<>(exactMethodMap);
|
||||||
|
|
||||||
debugInformation.statementStartMapping = statementStartMapping.build();
|
debugInformation.statementStartMapping = statementStartMapping.build();
|
||||||
debugInformation.fileMapping = compress(fileMapping).build();
|
|
||||||
debugInformation.lineMapping = compress(lineMapping).build();
|
DebugInformation.Layer[] builtLayers = new DebugInformation.Layer[layers.size()];
|
||||||
debugInformation.classMapping = compress(classMapping).build();
|
for (int i = 0; i < builtLayers.length; ++i) {
|
||||||
debugInformation.methodMapping = compress(methodMapping).build();
|
LayerBuilder layerBuilder = layers.get(i);
|
||||||
|
DebugInformation.Layer builtLayer = new DebugInformation.Layer();
|
||||||
|
builtLayer.fileMapping = compress(layerBuilder.fileMapping).build();
|
||||||
|
builtLayer.lineMapping = compress(layerBuilder.lineMapping).build();
|
||||||
|
builtLayer.classMapping = compress(layerBuilder.classMapping).build();
|
||||||
|
builtLayer.methodMapping = compress(layerBuilder.methodMapping).build();
|
||||||
|
builtLayers[i] = builtLayer;
|
||||||
|
}
|
||||||
|
debugInformation.layers = builtLayers;
|
||||||
|
|
||||||
debugInformation.callSiteMapping = callSiteMapping.build();
|
debugInformation.callSiteMapping = callSiteMapping.build();
|
||||||
debugInformation.variableMappings = new RecordArray[variableNames.list.size()];
|
debugInformation.variableMappings = new RecordArray[variableNames.list.size()];
|
||||||
for (int var : variableMappings.keySet()) {
|
for (int var : variableMappings.keySet()) {
|
||||||
|
@ -339,7 +361,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getItems() {
|
public String[] getItems() {
|
||||||
return list.toArray(new String[list.size()]);
|
return list.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Integer> getIndexes() {
|
public Map<String, Integer> getIndexes() {
|
||||||
|
@ -352,4 +374,15 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
String jsName;
|
String jsName;
|
||||||
Map<Integer, Integer> fieldMap = new HashMap<>();
|
Map<Integer, Integer> fieldMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class LayerBuilder {
|
||||||
|
private RecordArrayBuilder fileMapping = new RecordArrayBuilder(3, 0);
|
||||||
|
private RecordArrayBuilder lineMapping = new RecordArrayBuilder(3, 0);
|
||||||
|
private RecordArrayBuilder classMapping = new RecordArrayBuilder(3, 0);
|
||||||
|
private RecordArrayBuilder methodMapping = new RecordArrayBuilder(3, 0);
|
||||||
|
private MethodDescriptor currentMethod;
|
||||||
|
private String currentClass;
|
||||||
|
private String currentFileName;
|
||||||
|
private int currentLine;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,10 @@ public interface DebugInformationEmitter {
|
||||||
|
|
||||||
void emitLocation(String fileName, int line);
|
void emitLocation(String fileName, int line);
|
||||||
|
|
||||||
|
void enterLocation();
|
||||||
|
|
||||||
|
void exitLocation();
|
||||||
|
|
||||||
void emitStatementStart();
|
void emitStatementStart();
|
||||||
|
|
||||||
void emitMethod(MethodDescriptor method);
|
void emitMethod(MethodDescriptor method);
|
||||||
|
|
|
@ -43,10 +43,15 @@ class DebugInformationReader {
|
||||||
debugInfo.methods = readStrings();
|
debugInfo.methods = readStrings();
|
||||||
debugInfo.variableNames = readStrings();
|
debugInfo.variableNames = readStrings();
|
||||||
debugInfo.exactMethods = readExactMethods();
|
debugInfo.exactMethods = readExactMethods();
|
||||||
debugInfo.fileMapping = readMapping();
|
debugInfo.layers = new DebugInformation.Layer[input.read()];
|
||||||
debugInfo.lineMapping = readMapping();
|
for (int i = 0; i < debugInfo.layers.length; ++i) {
|
||||||
debugInfo.classMapping = readMapping();
|
DebugInformation.Layer layer = new DebugInformation.Layer();
|
||||||
debugInfo.methodMapping = readMapping();
|
layer.fileMapping = readMapping();
|
||||||
|
layer.lineMapping = readMapping();
|
||||||
|
layer.classMapping = readMapping();
|
||||||
|
layer.methodMapping = readMapping();
|
||||||
|
debugInfo.layers[i] = layer;
|
||||||
|
}
|
||||||
debugInfo.statementStartMapping = readBooleanMapping();
|
debugInfo.statementStartMapping = readBooleanMapping();
|
||||||
debugInfo.callSiteMapping = readCallSiteMapping();
|
debugInfo.callSiteMapping = readCallSiteMapping();
|
||||||
debugInfo.variableMappings = readVariableMappings(debugInfo.variableNames.length);
|
debugInfo.variableMappings = readVariableMappings(debugInfo.variableNames.length);
|
||||||
|
|
|
@ -42,10 +42,13 @@ class DebugInformationWriter {
|
||||||
writeStringArray(debugInfo.variableNames);
|
writeStringArray(debugInfo.variableNames);
|
||||||
writeExactMethods(debugInfo.exactMethods);
|
writeExactMethods(debugInfo.exactMethods);
|
||||||
|
|
||||||
writeMapping(debugInfo.fileMapping);
|
output.write(debugInfo.layers.length);
|
||||||
writeMapping(debugInfo.lineMapping);
|
for (DebugInformation.Layer layer : debugInfo.layers) {
|
||||||
writeMapping(debugInfo.classMapping);
|
writeMapping(layer.fileMapping);
|
||||||
writeMapping(debugInfo.methodMapping);
|
writeMapping(layer.lineMapping);
|
||||||
|
writeMapping(layer.classMapping);
|
||||||
|
writeMapping(layer.methodMapping);
|
||||||
|
}
|
||||||
writeLinesAndColumns(debugInfo.statementStartMapping);
|
writeLinesAndColumns(debugInfo.statementStartMapping);
|
||||||
writeCallSiteMapping(debugInfo.callSiteMapping);
|
writeCallSiteMapping(debugInfo.callSiteMapping);
|
||||||
writeVariableMappings(debugInfo);
|
writeVariableMappings(debugInfo);
|
||||||
|
|
|
@ -24,6 +24,16 @@ public class DummyDebugInformationEmitter implements DebugInformationEmitter {
|
||||||
public void emitLocation(String fileName, int line) {
|
public void emitLocation(String fileName, int line) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enterLocation() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exitLocation() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emitMethod(MethodDescriptor method) {
|
public void emitMethod(MethodDescriptor method) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,29 +21,30 @@ import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public class ExactMethodIterator {
|
public class ExactMethodIterator {
|
||||||
private DebugInformation debugInformation;
|
private DebugInformation debugInformation;
|
||||||
|
private DebugInformation.Layer layer;
|
||||||
private GeneratedLocation location;
|
private GeneratedLocation location;
|
||||||
private int classIndex;
|
private int classIndex;
|
||||||
private int methodIndex;
|
private int methodIndex;
|
||||||
private int classId = -1;
|
private int classId = -1;
|
||||||
private int methodId = -1;
|
private int methodId = -1;
|
||||||
|
|
||||||
ExactMethodIterator(DebugInformation debugInformation) {
|
ExactMethodIterator(DebugInformation debugInformation, DebugInformation.Layer layer) {
|
||||||
this.debugInformation = debugInformation;
|
this.debugInformation = debugInformation;
|
||||||
|
this.layer = layer;
|
||||||
if (!isEndReached()) {
|
if (!isEndReached()) {
|
||||||
read();
|
read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEndReached() {
|
public boolean isEndReached() {
|
||||||
return methodIndex >= debugInformation.methodMapping.size()
|
return methodIndex >= layer.methodMapping.size() && classIndex >= layer.classMapping.size();
|
||||||
&& classIndex >= debugInformation.classMapping.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void read() {
|
private void read() {
|
||||||
if (classIndex < debugInformation.classMapping.size()
|
if (classIndex < layer.classMapping.size()
|
||||||
&& methodIndex < debugInformation.methodMapping.size()) {
|
&& methodIndex < layer.methodMapping.size()) {
|
||||||
RecordArray.Record classRecord = debugInformation.classMapping.get(classIndex);
|
RecordArray.Record classRecord = layer.classMapping.get(classIndex);
|
||||||
RecordArray.Record methodRecord = debugInformation.methodMapping.get(methodIndex);
|
RecordArray.Record methodRecord = layer.methodMapping.get(methodIndex);
|
||||||
GeneratedLocation classLoc = DebugInformation.key(classRecord);
|
GeneratedLocation classLoc = DebugInformation.key(classRecord);
|
||||||
GeneratedLocation methodLoc = DebugInformation.key(methodRecord);
|
GeneratedLocation methodLoc = DebugInformation.key(methodRecord);
|
||||||
int cmp = classLoc.compareTo(methodLoc);
|
int cmp = classLoc.compareTo(methodLoc);
|
||||||
|
@ -55,9 +56,9 @@ public class ExactMethodIterator {
|
||||||
nextClassRecord();
|
nextClassRecord();
|
||||||
nextMethodRecord();
|
nextMethodRecord();
|
||||||
}
|
}
|
||||||
} else if (classIndex < debugInformation.classMapping.size()) {
|
} else if (classIndex < layer.classMapping.size()) {
|
||||||
nextClassRecord();
|
nextClassRecord();
|
||||||
} else if (methodIndex < debugInformation.methodMapping.size()) {
|
} else if (methodIndex < layer.methodMapping.size()) {
|
||||||
nextMethodRecord();
|
nextMethodRecord();
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("End already reached");
|
throw new IllegalStateException("End already reached");
|
||||||
|
@ -65,13 +66,13 @@ public class ExactMethodIterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void nextClassRecord() {
|
private void nextClassRecord() {
|
||||||
RecordArray.Record record = debugInformation.classMapping.get(classIndex++);
|
RecordArray.Record record = layer.classMapping.get(classIndex++);
|
||||||
classId = record.get(2);
|
classId = record.get(2);
|
||||||
location = DebugInformation.key(record);
|
location = DebugInformation.key(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void nextMethodRecord() {
|
private void nextMethodRecord() {
|
||||||
RecordArray.Record record = debugInformation.methodMapping.get(methodIndex++);
|
RecordArray.Record record = layer.methodMapping.get(methodIndex++);
|
||||||
methodId = record.get(2);
|
methodId = record.get(2);
|
||||||
location = DebugInformation.key(record);
|
location = DebugInformation.key(record);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.information;
|
|
||||||
|
|
||||||
public class FileNameIterator {
|
|
||||||
private DebugInformation debugInformation;
|
|
||||||
private int index;
|
|
||||||
|
|
||||||
FileNameIterator(DebugInformation debugInformation) {
|
|
||||||
this.debugInformation = debugInformation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEndReached() {
|
|
||||||
return index < debugInformation.fileMapping.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeneratedLocation getLocation() {
|
|
||||||
if (isEndReached()) {
|
|
||||||
throw new IllegalStateException("End already reached");
|
|
||||||
}
|
|
||||||
return DebugInformation.key(debugInformation.fileMapping.get(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getFileNameId() {
|
|
||||||
if (isEndReached()) {
|
|
||||||
throw new IllegalStateException("End already reached");
|
|
||||||
}
|
|
||||||
return debugInformation.fileMapping.get(index).get(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFileName() {
|
|
||||||
int fileNameId = getFileNameId();
|
|
||||||
return fileNameId >= 0 ? debugInformation.getFileName(fileNameId) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void next() {
|
|
||||||
if (isEndReached()) {
|
|
||||||
throw new IllegalStateException("End already reached");
|
|
||||||
}
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 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.information;
|
||||||
|
|
||||||
|
class LayerIterator {
|
||||||
|
private int currentLayer;
|
||||||
|
private MethodIterator[] methodIterators;
|
||||||
|
private GeneratedLocation currentLocation;
|
||||||
|
|
||||||
|
LayerIterator(DebugInformation debugInformation) {
|
||||||
|
methodIterators = new MethodIterator[debugInformation.layerCount()];
|
||||||
|
for (int i = 0; i < methodIterators.length; ++i) {
|
||||||
|
methodIterators[i] = new MethodIterator(debugInformation.layers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEndReached() {
|
||||||
|
return currentLayer == 0 && methodIterators[currentLayer].isEndReached();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLayer() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
return currentLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneratedLocation getLocation() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
return currentLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
int previous = currentLayer;
|
||||||
|
do {
|
||||||
|
nextImpl();
|
||||||
|
} while (!isEndReached() && previous == currentLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nextImpl() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canEnterLayer()) {
|
||||||
|
++currentLayer;
|
||||||
|
while (canEnterLayer()) {
|
||||||
|
++currentLayer;
|
||||||
|
}
|
||||||
|
currentLocation = methodIterators[currentLayer].getLocation();
|
||||||
|
methodIterators[currentLayer].next();
|
||||||
|
} else if (canExitLayer()) {
|
||||||
|
GeneratedLocation limitLocation = methodIterators[currentLayer].getLocation();
|
||||||
|
moveToNextNotEmpty();
|
||||||
|
while (true) {
|
||||||
|
--currentLayer;
|
||||||
|
moveToLocation(limitLocation);
|
||||||
|
if (currentLayer <= 0 || methodIterators[currentLayer].getMethodId() >= 0
|
||||||
|
|| !methodIterators[currentLayer].getLocation().equals(limitLocation)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
moveToNextNotEmpty();
|
||||||
|
}
|
||||||
|
currentLocation = limitLocation;
|
||||||
|
} else {
|
||||||
|
currentLocation = methodIterators[currentLayer].getLocation();
|
||||||
|
methodIterators[currentLayer].next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canEnterLayer() {
|
||||||
|
return currentLayer < methodIterators.length - 1
|
||||||
|
&& !methodIterators[currentLayer + 1].isEndReached()
|
||||||
|
&& !methodIterators[currentLayer].isEndReached()
|
||||||
|
&& isLocationLessOrEqual(currentLayer + 1, currentLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canExitLayer() {
|
||||||
|
if (currentLayer == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return methodIterators[currentLayer].getMethodId() < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveToNextNotEmpty() {
|
||||||
|
while (!methodIterators[currentLayer].isEndReached() && methodIterators[currentLayer].getMethodId() < 0) {
|
||||||
|
methodIterators[currentLayer].next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void moveToLocation(GeneratedLocation location) {
|
||||||
|
while (true) {
|
||||||
|
GeneratedLocation nextLocation = methodIterators[currentLayer].getLocation();
|
||||||
|
if (nextLocation.compareTo(location) >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
currentLocation = location;
|
||||||
|
methodIterators[currentLayer].next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLocationLessOrEqual(int firstLayer, int secondLayer) {
|
||||||
|
return methodIterators[firstLayer].getLocation().compareTo(methodIterators[secondLayer].getLocation()) <= 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 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.information;
|
||||||
|
|
||||||
|
import org.teavm.common.RecordArray;
|
||||||
|
|
||||||
|
class LayerSourceLocationIterator {
|
||||||
|
private DebugInformation debugInformation;
|
||||||
|
private int lineIndex;
|
||||||
|
private int fileIndex;
|
||||||
|
private GeneratedLocation location;
|
||||||
|
private int fileId = -1;
|
||||||
|
private int line = -1;
|
||||||
|
private boolean endReached;
|
||||||
|
private DebugInformation.Layer layer;
|
||||||
|
|
||||||
|
LayerSourceLocationIterator(DebugInformation debugInformation, DebugInformation.Layer layer) {
|
||||||
|
this.debugInformation = debugInformation;
|
||||||
|
this.layer = layer;
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEndReached() {
|
||||||
|
return endReached;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void read() {
|
||||||
|
if (fileIndex < layer.fileMapping.size() && lineIndex < layer.lineMapping.size()) {
|
||||||
|
RecordArray.Record fileRecord = layer.fileMapping.get(fileIndex);
|
||||||
|
RecordArray.Record lineRecord = layer.lineMapping.get(lineIndex);
|
||||||
|
GeneratedLocation fileLoc = DebugInformation.key(fileRecord);
|
||||||
|
GeneratedLocation lineLoc = DebugInformation.key(lineRecord);
|
||||||
|
int cmp = fileLoc.compareTo(lineLoc);
|
||||||
|
if (cmp < 0) {
|
||||||
|
nextFileRecord();
|
||||||
|
} else if (cmp > 0) {
|
||||||
|
nextLineRecord();
|
||||||
|
} else {
|
||||||
|
nextFileRecord();
|
||||||
|
nextLineRecord();
|
||||||
|
}
|
||||||
|
} else if (fileIndex < layer.fileMapping.size()) {
|
||||||
|
nextFileRecord();
|
||||||
|
} else if (lineIndex < layer.lineMapping.size()) {
|
||||||
|
nextLineRecord();
|
||||||
|
} else if (endReached) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
} else {
|
||||||
|
endReached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nextFileRecord() {
|
||||||
|
RecordArray.Record record = layer.fileMapping.get(fileIndex++);
|
||||||
|
location = DebugInformation.key(record);
|
||||||
|
fileId = record.get(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nextLineRecord() {
|
||||||
|
RecordArray.Record record = layer.lineMapping.get(lineIndex++);
|
||||||
|
location = DebugInformation.key(record);
|
||||||
|
line = record.get(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneratedLocation getLocation() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFileNameId() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
int fileId = getFileNameId();
|
||||||
|
return fileId >= 0 ? debugInformation.getFileName(fileId) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLine() {
|
||||||
|
if (isEndReached()) {
|
||||||
|
throw new IllegalStateException("End already reached");
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.information;
|
|
||||||
|
|
||||||
public class LineNumberIterator {
|
|
||||||
private DebugInformation debugInformation;
|
|
||||||
private int index;
|
|
||||||
|
|
||||||
LineNumberIterator(DebugInformation debugInformation) {
|
|
||||||
this.debugInformation = debugInformation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEndReached() {
|
|
||||||
return index < debugInformation.lineMapping.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeneratedLocation getLocation() {
|
|
||||||
if (isEndReached()) {
|
|
||||||
throw new IllegalStateException("End already reached");
|
|
||||||
}
|
|
||||||
return DebugInformation.key(debugInformation.lineMapping.get(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLineNumber() {
|
|
||||||
if (isEndReached()) {
|
|
||||||
throw new IllegalStateException("End already reached");
|
|
||||||
}
|
|
||||||
return debugInformation.lineMapping.get(index).get(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void next() {
|
|
||||||
if (isEndReached()) {
|
|
||||||
throw new IllegalStateException("End already reached");
|
|
||||||
}
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,37 +15,30 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.debugging.information;
|
package org.teavm.debugging.information;
|
||||||
|
|
||||||
import org.teavm.model.MethodDescriptor;
|
class MethodIterator {
|
||||||
|
private DebugInformation.Layer layer;
|
||||||
public class MethodIterator {
|
|
||||||
private DebugInformation debugInformation;
|
|
||||||
private int index;
|
private int index;
|
||||||
|
|
||||||
MethodIterator(DebugInformation debugInformation) {
|
MethodIterator(DebugInformation.Layer layer) {
|
||||||
this.debugInformation = debugInformation;
|
this.layer = layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEndReached() {
|
public boolean isEndReached() {
|
||||||
return index < debugInformation.methodMapping.size();
|
return index >= layer.methodMapping.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeneratedLocation getLocation() {
|
public GeneratedLocation getLocation() {
|
||||||
if (isEndReached()) {
|
if (isEndReached()) {
|
||||||
throw new IllegalStateException("End already reached");
|
throw new IllegalStateException("End already reached");
|
||||||
}
|
}
|
||||||
return DebugInformation.key(debugInformation.methodMapping.get(index));
|
return DebugInformation.key(layer.methodMapping.get(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMethodId() {
|
public int getMethodId() {
|
||||||
if (isEndReached()) {
|
if (isEndReached()) {
|
||||||
throw new IllegalStateException("End already reached");
|
throw new IllegalStateException("End already reached");
|
||||||
}
|
}
|
||||||
return debugInformation.methodMapping.get(index).get(2);
|
return layer.methodMapping.get(index).get(2);
|
||||||
}
|
|
||||||
|
|
||||||
public MethodDescriptor getMethod() {
|
|
||||||
int methodId = getMethodId();
|
|
||||||
return methodId >= 0 ? debugInformation.getMethod(methodId) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
|
|
|
@ -15,85 +15,77 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.debugging.information;
|
package org.teavm.debugging.information;
|
||||||
|
|
||||||
import org.teavm.common.RecordArray;
|
|
||||||
|
|
||||||
public class SourceLocationIterator {
|
public class SourceLocationIterator {
|
||||||
private DebugInformation debugInformation;
|
private DebugInformation debugInformation;
|
||||||
private int lineIndex;
|
private LayerIterator layerIterator;
|
||||||
private int fileIndex;
|
private LayerInfo[] layerSourceIterators;
|
||||||
private GeneratedLocation location;
|
|
||||||
private int fileId = -1;
|
|
||||||
private int line = -1;
|
|
||||||
private boolean endReached;
|
private boolean endReached;
|
||||||
|
private int currentLayer;
|
||||||
|
private GeneratedLocation lastLocation;
|
||||||
|
|
||||||
SourceLocationIterator(DebugInformation debugInformation) {
|
public SourceLocationIterator(DebugInformation debugInformation) {
|
||||||
this.debugInformation = debugInformation;
|
this.debugInformation = debugInformation;
|
||||||
if (!isEndReached()) {
|
layerIterator = new LayerIterator(debugInformation);
|
||||||
read();
|
layerSourceIterators = new LayerInfo[debugInformation.layerCount()];
|
||||||
|
for (int i = 0; i < layerSourceIterators.length; ++i) {
|
||||||
|
layerSourceIterators[i] = new LayerInfo(new LayerSourceLocationIterator(
|
||||||
|
debugInformation, debugInformation.layers[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!layerIterator.isEndReached()) {
|
||||||
|
currentLayer = layerIterator.getLayer();
|
||||||
|
layerIterator.next();
|
||||||
|
} else {
|
||||||
|
currentLayer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLocation = layerSourceIterators[currentLayer].lastLocation;
|
||||||
|
if (lastLocation == null) {
|
||||||
|
endReached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeneratedLocation getLocation() {
|
||||||
|
return lastLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEndReached() {
|
public boolean isEndReached() {
|
||||||
return endReached;
|
return endReached;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void read() {
|
|
||||||
if (fileIndex < debugInformation.fileMapping.size() && lineIndex < debugInformation.lineMapping.size()) {
|
|
||||||
RecordArray.Record fileRecord = debugInformation.fileMapping.get(fileIndex);
|
|
||||||
RecordArray.Record lineRecord = debugInformation.lineMapping.get(lineIndex);
|
|
||||||
GeneratedLocation fileLoc = DebugInformation.key(fileRecord);
|
|
||||||
GeneratedLocation lineLoc = DebugInformation.key(lineRecord);
|
|
||||||
int cmp = fileLoc.compareTo(lineLoc);
|
|
||||||
if (cmp < 0) {
|
|
||||||
nextFileRecord();
|
|
||||||
} else if (cmp > 0) {
|
|
||||||
nextLineRecord();
|
|
||||||
} else {
|
|
||||||
nextFileRecord();
|
|
||||||
nextLineRecord();
|
|
||||||
}
|
|
||||||
} else if (fileIndex < debugInformation.fileMapping.size()) {
|
|
||||||
nextFileRecord();
|
|
||||||
} else if (lineIndex < debugInformation.lineMapping.size()) {
|
|
||||||
nextLineRecord();
|
|
||||||
} else if (endReached) {
|
|
||||||
throw new IllegalStateException("End already reached");
|
|
||||||
} else {
|
|
||||||
endReached = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void nextFileRecord() {
|
|
||||||
RecordArray.Record record = debugInformation.fileMapping.get(fileIndex++);
|
|
||||||
location = DebugInformation.key(record);
|
|
||||||
fileId = record.get(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void nextLineRecord() {
|
|
||||||
RecordArray.Record record = debugInformation.lineMapping.get(lineIndex++);
|
|
||||||
location = DebugInformation.key(record);
|
|
||||||
line = record.get(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
if (isEndReached()) {
|
if (endReached) {
|
||||||
throw new IllegalStateException("End already reached");
|
throw new IllegalStateException();
|
||||||
}
|
|
||||||
read();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeneratedLocation getLocation() {
|
LayerInfo currentIterator = layerSourceIterators[currentLayer];
|
||||||
if (isEndReached()) {
|
if (currentLayer == 0 && currentIterator.iterator.isEndReached()) {
|
||||||
throw new IllegalStateException("End already reached");
|
endReached = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentIterator.iterator.isEndReached() || (!layerIterator.isEndReached()
|
||||||
|
&& currentIterator.iterator.getLocation().compareTo(layerIterator.getLocation()) >= 0)) {
|
||||||
|
currentLayer = layerIterator.getLayer();
|
||||||
|
lastLocation = layerIterator.getLocation();
|
||||||
|
layerIterator.next();
|
||||||
|
|
||||||
|
currentIterator = layerSourceIterators[currentLayer];
|
||||||
|
while (!currentIterator.iterator.isEndReached()
|
||||||
|
&& currentIterator.iterator.getLocation().compareTo(lastLocation) <= 0) {
|
||||||
|
currentIterator.next();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentIterator.next();
|
||||||
|
lastLocation = currentIterator.lastLocation;
|
||||||
}
|
}
|
||||||
return location;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFileNameId() {
|
public int getFileNameId() {
|
||||||
if (isEndReached()) {
|
if (isEndReached()) {
|
||||||
throw new IllegalStateException("End already reached");
|
throw new IllegalStateException("End already reached");
|
||||||
}
|
}
|
||||||
return fileId;
|
return layerSourceIterators[currentLayer].lastFileId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFileName() {
|
public String getFileName() {
|
||||||
|
@ -105,6 +97,27 @@ public class SourceLocationIterator {
|
||||||
if (isEndReached()) {
|
if (isEndReached()) {
|
||||||
throw new IllegalStateException("End already reached");
|
throw new IllegalStateException("End already reached");
|
||||||
}
|
}
|
||||||
return line;
|
return layerSourceIterators[currentLayer].lastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LayerInfo {
|
||||||
|
LayerSourceLocationIterator iterator;
|
||||||
|
int lastFileId;
|
||||||
|
int lastLine;
|
||||||
|
GeneratedLocation lastLocation;
|
||||||
|
|
||||||
|
LayerInfo(LayerSourceLocationIterator iterator) {
|
||||||
|
this.iterator = iterator;
|
||||||
|
if (!iterator.isEndReached()) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void next() {
|
||||||
|
this.lastFileId = iterator.getFileNameId();
|
||||||
|
this.lastLine = iterator.getLine();
|
||||||
|
this.lastLocation = iterator.getLocation();
|
||||||
|
iterator.next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@ class SourceMapsWriter {
|
||||||
output.write("\"}");
|
output.write("\"}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeSegment(GeneratedLocation loc, int sourceFile, int sourceLine) throws IOException {
|
private void writeSegment(GeneratedLocation loc, int sourceFile, int sourceLine)
|
||||||
|
throws IOException {
|
||||||
while (loc.getLine() > lastLine) {
|
while (loc.getLine() > lastLine) {
|
||||||
output.write(';');
|
output.write(';');
|
||||||
++lastLine;
|
++lastLine;
|
||||||
|
|
|
@ -398,7 +398,7 @@ public class Inlining {
|
||||||
entry.targetInstruction = insn;
|
entry.targetInstruction = insn;
|
||||||
entry.program = invokedProgram;
|
entry.program = invokedProgram;
|
||||||
entry.innerPlan.addAll(buildPlan(invokedProgram, depth + 1, innerStep, invokedMethod.getReference(),
|
entry.innerPlan.addAll(buildPlan(invokedProgram, depth + 1, innerStep, invokedMethod.getReference(),
|
||||||
inliningInfo));
|
innerInliningInfo));
|
||||||
entry.depth = depth;
|
entry.depth = depth;
|
||||||
entry.method = invokedMethod.getReference();
|
entry.method = invokedMethod.getReference();
|
||||||
entry.locationInfo = innerInliningInfo;
|
entry.locationInfo = innerInliningInfo;
|
||||||
|
|
|
@ -61,7 +61,7 @@ class LocationGraphBuilder {
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
Step step = stack.pop();
|
Step step = stack.pop();
|
||||||
if (visited[step.block]) {
|
if (visited[step.block]) {
|
||||||
if (step.location != null) {
|
if (step.location != null && !step.location.isEmpty()) {
|
||||||
additionalConnections.add(new AdditionalConnection(step.location, startLocations.get(step.block)));
|
additionalConnections.add(new AdditionalConnection(step.location, startLocations.get(step.block)));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -83,14 +83,14 @@ class LocationGraphBuilder {
|
||||||
if (blockLocations[step.block] == null) {
|
if (blockLocations[step.block] == null) {
|
||||||
blockLocations[step.block] = insn.getLocation();
|
blockLocations[step.block] = insn.getLocation();
|
||||||
}
|
}
|
||||||
if (location != null && !Objects.equals(location, insn.getLocation())) {
|
if (location != null && !location.isEmpty() && !Objects.equals(location, insn.getLocation())) {
|
||||||
addEdge(location, insn.getLocation());
|
addEdge(location, insn.getLocation());
|
||||||
}
|
}
|
||||||
location = insn.getLocation();
|
location = insn.getLocation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (graph.outgoingEdgesCount(step.block) == 0) {
|
if (graph.outgoingEdgesCount(step.block) == 0) {
|
||||||
if (location != null) {
|
if (location != null && !location.isEmpty()) {
|
||||||
addEdge(location, new TextLocation(null, -1));
|
addEdge(location, new TextLocation(null, -1));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,8 +17,11 @@ package org.teavm.devserver.deobfuscate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.debugging.information.DebugInformation;
|
import org.teavm.debugging.information.DebugInformation;
|
||||||
|
import org.teavm.debugging.information.GeneratedLocation;
|
||||||
import org.teavm.debugging.information.SourceLocation;
|
import org.teavm.debugging.information.SourceLocation;
|
||||||
import org.teavm.jso.JSBody;
|
import org.teavm.jso.JSBody;
|
||||||
import org.teavm.jso.ajax.XMLHttpRequest;
|
import org.teavm.jso.ajax.XMLHttpRequest;
|
||||||
|
@ -71,11 +74,12 @@ public final class Deobfuscator {
|
||||||
String fileName = groups.get(2).stringValue();
|
String fileName = groups.get(2).stringValue();
|
||||||
int lineNumber = Integer.parseInt(groups.get(3).stringValue());
|
int lineNumber = Integer.parseInt(groups.get(3).stringValue());
|
||||||
int columnNumber = Integer.parseInt(groups.get(4).stringValue());
|
int columnNumber = Integer.parseInt(groups.get(4).stringValue());
|
||||||
Frame frame = deobfuscateFrame(debugInformation, classesFileName, fileName, lineNumber, columnNumber);
|
List<Frame> framesPerLine = deobfuscateFrames(debugInformation, classesFileName, fileName,
|
||||||
if (frame == null) {
|
lineNumber, columnNumber);
|
||||||
frame = createDefaultFrame(fileName, functionName, lineNumber);
|
if (framesPerLine == null) {
|
||||||
|
framesPerLine = Arrays.asList(createDefaultFrame(fileName, functionName, lineNumber));
|
||||||
}
|
}
|
||||||
frames.add(frame);
|
frames.addAll(framesPerLine);
|
||||||
}
|
}
|
||||||
return frames.toArray(new Frame[0]);
|
return frames.toArray(new Frame[0]);
|
||||||
});
|
});
|
||||||
|
@ -85,18 +89,22 @@ public final class Deobfuscator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Frame deobfuscateFrame(DebugInformation debugInformation, String classesFileName,
|
private static List<Frame> deobfuscateFrames(DebugInformation debugInformation, String classesFileName,
|
||||||
String fileName, int lineNumber, int columnNumber) {
|
String fileName, int lineNumber, int columnNumber) {
|
||||||
if (!fileName.equals(classesFileName)) {
|
if (!fileName.equals(classesFileName)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodReference method = debugInformation.getMethodAt(lineNumber - 1, columnNumber - 1);
|
List<Frame> result = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int layer = 0; layer < debugInformation.layerCount(); ++layer) {
|
||||||
|
GeneratedLocation jsLocation = new GeneratedLocation(lineNumber - 1, columnNumber - 1);
|
||||||
|
MethodReference method = debugInformation.getMethodAt(jsLocation, layer);
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
return null;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLocation location = debugInformation.getSourceLocation(lineNumber - 1, columnNumber - 1);
|
SourceLocation location = debugInformation.getSourceLocation(jsLocation, layer);
|
||||||
|
|
||||||
String decodedFileName = location != null ? location.getFileName() : null;
|
String decodedFileName = location != null ? location.getFileName() : null;
|
||||||
if (decodedFileName != null) {
|
if (decodedFileName != null) {
|
||||||
|
@ -110,7 +118,13 @@ public final class Deobfuscator {
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
frame.setLineNumber(location.getLine());
|
frame.setLineNumber(location.getLine());
|
||||||
}
|
}
|
||||||
return frame;
|
}
|
||||||
|
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Collections.reverse(result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Frame createDefaultFrame(String fileName, String functionName, int lineNumber) {
|
private static Frame createDefaultFrame(String fileName, String functionName, int lineNumber) {
|
||||||
|
|
|
@ -25,16 +25,18 @@ import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
|
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
|
||||||
import org.teavm.debugging.information.DebugInformation;
|
import org.teavm.debugging.information.DebugInformation;
|
||||||
|
import org.teavm.debugging.information.GeneratedLocation;
|
||||||
import org.teavm.debugging.information.SourceLocation;
|
import org.teavm.debugging.information.SourceLocation;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
final class RhinoResultParser {
|
final class RhinoResultParser {
|
||||||
private static Pattern pattern = Pattern.compile("(([A-Za-z_$]+)\\(\\))?@.+:([0-9]+)");
|
private static Pattern pattern = Pattern.compile("(([A-Za-z_$][A-Za-z0-9_$]*)\\(\\))?@.+:([0-9]+)");
|
||||||
private static Pattern lineSeparator = Pattern.compile("\\r\\n|\r|\n");
|
private static Pattern lineSeparator = Pattern.compile("\\r\\n|\r|\n");
|
||||||
private DebugInformation debugInformation;
|
private DebugInformation debugInformation;
|
||||||
private String[] script;
|
private String[] script;
|
||||||
|
@ -70,8 +72,7 @@ final class RhinoResultParser {
|
||||||
String stack = result.get("stack", result).toString();
|
String stack = result.get("stack", result).toString();
|
||||||
StackTraceElement[] decodedStack = null;
|
StackTraceElement[] decodedStack = null;
|
||||||
if (debugInformation != null) {
|
if (debugInformation != null) {
|
||||||
List<StackTraceElement> elements = new ArrayList<>();
|
List<StackTraceElement> elements = new ArrayList<>(Arrays.asList(decodeStack(stack)));
|
||||||
elements.addAll(Arrays.asList(decodeStack(stack)));
|
|
||||||
List<StackTraceElement> currentElements = Arrays.asList(Thread.currentThread().getStackTrace());
|
List<StackTraceElement> currentElements = Arrays.asList(Thread.currentThread().getStackTrace());
|
||||||
elements.addAll(currentElements.subList(2, currentElements.size()));
|
elements.addAll(currentElements.subList(2, currentElements.size()));
|
||||||
decodedStack = elements.toArray(new StackTraceElement[0]);
|
decodedStack = elements.toArray(new StackTraceElement[0]);
|
||||||
|
@ -104,24 +105,33 @@ final class RhinoResultParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
String functionName = matcher.group(2);
|
String functionName = matcher.group(2);
|
||||||
int lineNumber = Integer.parseInt(matcher.group(3)) - 1;
|
int jsLineNumber = Integer.parseInt(matcher.group(3)) - 1;
|
||||||
|
|
||||||
String scriptLine = script[lineNumber];
|
String scriptLine = script[jsLineNumber];
|
||||||
int column = firstNonSpace(scriptLine);
|
int jsColumn = firstNonSpace(scriptLine);
|
||||||
MethodReference method = debugInformation.getMethodAt(lineNumber, column);
|
|
||||||
|
int layer = 0;
|
||||||
|
List<StackTraceElement> elementsByLine = new ArrayList<>();
|
||||||
|
GeneratedLocation jsLocation = new GeneratedLocation(jsLineNumber, jsColumn);
|
||||||
|
while (true) {
|
||||||
|
int lineNumber = jsLineNumber;
|
||||||
|
|
||||||
|
MethodReference method = debugInformation.getMethodAt(jsLocation, layer);
|
||||||
String className;
|
String className;
|
||||||
String methodName;
|
String methodName;
|
||||||
|
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
className = method.getClassName();
|
className = method.getClassName();
|
||||||
methodName = method.getName();
|
methodName = method.getName();
|
||||||
|
} else if (layer > 0) {
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
className = "<JS>";
|
className = "<JS>";
|
||||||
methodName = functionName != null ? functionName : "<unknown_function>";
|
methodName = functionName != null ? functionName : "<unknown_function>";
|
||||||
}
|
}
|
||||||
|
|
||||||
String fileName;
|
String fileName;
|
||||||
SourceLocation location = debugInformation.getSourceLocation(lineNumber, column);
|
SourceLocation location = debugInformation.getSourceLocation(jsLocation, layer);
|
||||||
if (location != null && location.getFileName() != null) {
|
if (location != null && location.getFileName() != null) {
|
||||||
fileName = location.getFileName();
|
fileName = location.getFileName();
|
||||||
fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
|
fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
|
||||||
|
@ -131,7 +141,13 @@ final class RhinoResultParser {
|
||||||
lineNumber++;
|
lineNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.add(new StackTraceElement(className, methodName, fileName, lineNumber));
|
elementsByLine.add(new StackTraceElement(className, methodName, fileName, lineNumber));
|
||||||
|
|
||||||
|
++layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.reverse(elementsByLine);
|
||||||
|
elements.addAll(elementsByLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
return elements.toArray(new StackTraceElement[0]);
|
return elements.toArray(new StackTraceElement[0]);
|
||||||
|
|
|
@ -37,7 +37,7 @@ interface TeaVMTestConfiguration<T extends TeaVMTarget> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(TeaVM vm) {
|
public void apply(TeaVM vm) {
|
||||||
vm.setOptimizationLevel(TeaVMOptimizationLevel.FULL);
|
vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue
Block a user