mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Fix various issues in debugger
This commit is contained in:
parent
46ebc2d694
commit
db97b7f732
|
@ -29,7 +29,6 @@
|
||||||
</indentOptions>
|
</indentOptions>
|
||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
<codeStyleSettings language="JAVA">
|
<codeStyleSettings language="JAVA">
|
||||||
<option name="KEEP_LINE_BREAKS" value="false" />
|
|
||||||
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
||||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||||
|
|
|
@ -40,7 +40,7 @@ script:
|
||||||
- pushd tests/src/test/js
|
- pushd tests/src/test/js
|
||||||
- export DISPLAY=:99.0
|
- export DISPLAY=:99.0
|
||||||
- sh -e /etc/init.d/xvfb start
|
- sh -e /etc/init.d/xvfb start
|
||||||
- sleep 3
|
- sleep 10
|
||||||
- firefox index.html &
|
- firefox index.html &
|
||||||
- FIREFOX_PID=$!
|
- FIREFOX_PID=$!
|
||||||
- node start.js $BASE_PATH/tests/target/js-tests
|
- node start.js $BASE_PATH/tests/target/js-tests
|
||||||
|
|
|
@ -91,14 +91,16 @@ public class Decompiler {
|
||||||
private List<TryCatchBookmark> tryCatchBookmarks = new ArrayList<>();
|
private List<TryCatchBookmark> tryCatchBookmarks = new ArrayList<>();
|
||||||
private Deque<Block> stack;
|
private Deque<Block> stack;
|
||||||
private Program program;
|
private Program program;
|
||||||
|
private boolean friendlyToDebugger;
|
||||||
|
|
||||||
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set<MethodReference> asyncMethods,
|
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set<MethodReference> asyncMethods,
|
||||||
Set<MethodReference> asyncFamilyMethods) {
|
Set<MethodReference> asyncFamilyMethods, boolean friendlyToDebugger) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.asyncMethods = asyncMethods;
|
this.asyncMethods = asyncMethods;
|
||||||
splitMethods.addAll(asyncMethods);
|
splitMethods.addAll(asyncMethods);
|
||||||
splitMethods.addAll(asyncFamilyMethods);
|
splitMethods.addAll(asyncFamilyMethods);
|
||||||
|
this.friendlyToDebugger = friendlyToDebugger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodNodeCache getRegularMethodCache() {
|
public MethodNodeCache getRegularMethodCache() {
|
||||||
|
@ -275,7 +277,7 @@ public class Decompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
Optimizer optimizer = new Optimizer();
|
Optimizer optimizer = new Optimizer();
|
||||||
optimizer.optimize(methodNode, method.getProgram());
|
optimizer.optimize(methodNode, method.getProgram(), friendlyToDebugger);
|
||||||
methodNode.getModifiers().addAll(method.getModifiers());
|
methodNode.getModifiers().addAll(method.getModifiers());
|
||||||
|
|
||||||
return methodNode;
|
return methodNode;
|
||||||
|
@ -339,7 +341,7 @@ public class Decompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
Optimizer optimizer = new Optimizer();
|
Optimizer optimizer = new Optimizer();
|
||||||
optimizer.optimize(node, splitter);
|
optimizer.optimize(node, splitter, friendlyToDebugger);
|
||||||
node.getModifiers().addAll(method.getModifiers());
|
node.getModifiers().addAll(method.getModifiers());
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
|
|
@ -18,7 +18,9 @@ package org.teavm.ast.optimization;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import org.teavm.ast.AsyncMethodNode;
|
import org.teavm.ast.AsyncMethodNode;
|
||||||
import org.teavm.ast.AsyncMethodPart;
|
import org.teavm.ast.AsyncMethodPart;
|
||||||
|
import org.teavm.ast.MethodNode;
|
||||||
import org.teavm.ast.RegularMethodNode;
|
import org.teavm.ast.RegularMethodNode;
|
||||||
|
import org.teavm.ast.VariableNode;
|
||||||
import org.teavm.common.Graph;
|
import org.teavm.common.Graph;
|
||||||
import org.teavm.model.BasicBlock;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.Instruction;
|
import org.teavm.model.Instruction;
|
||||||
|
@ -31,13 +33,14 @@ import org.teavm.model.util.ProgramUtils;
|
||||||
import org.teavm.model.util.UsageExtractor;
|
import org.teavm.model.util.UsageExtractor;
|
||||||
|
|
||||||
public class Optimizer {
|
public class Optimizer {
|
||||||
public void optimize(RegularMethodNode method, Program program) {
|
public void optimize(RegularMethodNode method, Program program, boolean friendlyToDebugger) {
|
||||||
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
|
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
|
||||||
stats.analyze(program);
|
stats.analyze(program);
|
||||||
boolean[] preservedVars = new boolean[stats.writes.length];
|
boolean[] preservedVars = new boolean[stats.writes.length];
|
||||||
BreakEliminator breakEliminator = new BreakEliminator();
|
BreakEliminator breakEliminator = new BreakEliminator();
|
||||||
breakEliminator.eliminate(method.getBody());
|
breakEliminator.eliminate(method.getBody());
|
||||||
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads);
|
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
|
||||||
|
friendlyToDebugger);
|
||||||
method.getBody().acceptVisitor(optimizer);
|
method.getBody().acceptVisitor(optimizer);
|
||||||
method.setBody(optimizer.resultStmt);
|
method.setBody(optimizer.resultStmt);
|
||||||
int paramCount = method.getReference().parameterCount();
|
int paramCount = method.getReference().parameterCount();
|
||||||
|
@ -55,7 +58,7 @@ public class Optimizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter) {
|
public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter, boolean friendlyToDebugger) {
|
||||||
LivenessAnalyzer liveness = new LivenessAnalyzer();
|
LivenessAnalyzer liveness = new LivenessAnalyzer();
|
||||||
liveness.analyze(splitter.getOriginalProgram());
|
liveness.analyze(splitter.getOriginalProgram());
|
||||||
|
|
||||||
|
@ -70,7 +73,8 @@ public class Optimizer {
|
||||||
BreakEliminator breakEliminator = new BreakEliminator();
|
BreakEliminator breakEliminator = new BreakEliminator();
|
||||||
breakEliminator.eliminate(part.getStatement());
|
breakEliminator.eliminate(part.getStatement());
|
||||||
findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars);
|
findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars);
|
||||||
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads);
|
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
|
||||||
|
friendlyToDebugger);
|
||||||
part.getStatement().acceptVisitor(optimizer);
|
part.getStatement().acceptVisitor(optimizer);
|
||||||
part.setStatement(optimizer.resultStmt);
|
part.setStatement(optimizer.resultStmt);
|
||||||
}
|
}
|
||||||
|
@ -93,6 +97,14 @@ public class Optimizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void preserveDebuggableVars(boolean[] variablesToPreserve, MethodNode methodNode) {
|
||||||
|
for (VariableNode varNode : methodNode.getVariables()) {
|
||||||
|
if (varNode.getName() != null) {
|
||||||
|
variablesToPreserve[varNode.getIndex()] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void findEscapingLiveVars(LivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter,
|
private void findEscapingLiveVars(LivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter,
|
||||||
int partIndex, boolean[] output) {
|
int partIndex, boolean[] output) {
|
||||||
Program originalProgram = splitter.getOriginalProgram();
|
Program originalProgram = splitter.getOriginalProgram();
|
||||||
|
|
|
@ -15,8 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.ast.optimization;
|
package org.teavm.ast.optimization;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -58,6 +61,7 @@ import org.teavm.ast.UnaryOperation;
|
||||||
import org.teavm.ast.UnwrapArrayExpr;
|
import org.teavm.ast.UnwrapArrayExpr;
|
||||||
import org.teavm.ast.VariableExpr;
|
import org.teavm.ast.VariableExpr;
|
||||||
import org.teavm.ast.WhileStatement;
|
import org.teavm.ast.WhileStatement;
|
||||||
|
import org.teavm.model.TextLocation;
|
||||||
|
|
||||||
class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
private Expr resultExpr;
|
private Expr resultExpr;
|
||||||
|
@ -66,11 +70,17 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
private final int[] writeFrequencies;
|
private final int[] writeFrequencies;
|
||||||
private final int[] readFrequencies;
|
private final int[] readFrequencies;
|
||||||
private List<Statement> resultSequence;
|
private List<Statement> resultSequence;
|
||||||
|
private boolean friendlyToDebugger;
|
||||||
|
private TextLocation currentLocation;
|
||||||
|
private Deque<TextLocation> locationStack = new LinkedList<>();
|
||||||
|
private Deque<TextLocation> notNullLocationStack = new ArrayDeque<>();
|
||||||
|
|
||||||
OptimizingVisitor(boolean[] preservedVars, int[] writeFrequencies, int[] readFrequencies) {
|
OptimizingVisitor(boolean[] preservedVars, int[] writeFrequencies, int[] readFrequencies,
|
||||||
|
boolean friendlyToDebugger) {
|
||||||
this.preservedVars = preservedVars;
|
this.preservedVars = preservedVars;
|
||||||
this.writeFrequencies = writeFrequencies;
|
this.writeFrequencies = writeFrequencies;
|
||||||
this.readFrequencies = readFrequencies;
|
this.readFrequencies = readFrequencies;
|
||||||
|
this.friendlyToDebugger = friendlyToDebugger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isZero(Expr expr) {
|
private static boolean isZero(Expr expr) {
|
||||||
|
@ -81,74 +91,100 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
return expr instanceof BinaryExpr && ((BinaryExpr) expr).getOperation() == BinaryOperation.COMPARE;
|
return expr instanceof BinaryExpr && ((BinaryExpr) expr).getOperation() == BinaryOperation.COMPARE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pushLocation(TextLocation location) {
|
||||||
|
locationStack.push(location);
|
||||||
|
if (location != null) {
|
||||||
|
if (currentLocation != null) {
|
||||||
|
notNullLocationStack.push(currentLocation);
|
||||||
|
}
|
||||||
|
currentLocation = location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void popLocation() {
|
||||||
|
if (locationStack.pop() != null) {
|
||||||
|
currentLocation = notNullLocationStack.pollFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BinaryExpr expr) {
|
public void visit(BinaryExpr expr) {
|
||||||
switch (expr.getOperation()) {
|
pushLocation(expr.getLocation());
|
||||||
case AND:
|
try {
|
||||||
case OR:
|
|
||||||
resultExpr = expr;
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
expr.getSecondOperand().acceptVisitor(this);
|
|
||||||
Expr b = resultExpr;
|
|
||||||
if (b instanceof ConstantExpr && expr.getOperation() == BinaryOperation.SUBTRACT) {
|
|
||||||
if (tryMakePositive((ConstantExpr) b)) {
|
|
||||||
expr.setOperation(BinaryOperation.ADD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expr.getFirstOperand().acceptVisitor(this);
|
|
||||||
Expr a = resultExpr;
|
|
||||||
Expr p = a;
|
|
||||||
Expr q = b;
|
|
||||||
boolean invert = false;
|
|
||||||
if (isZero(p)) {
|
|
||||||
Expr tmp = p;
|
|
||||||
p = q;
|
|
||||||
q = tmp;
|
|
||||||
invert = true;
|
|
||||||
}
|
|
||||||
if (isComparison(p) && isZero(q)) {
|
|
||||||
switch (expr.getOperation()) {
|
switch (expr.getOperation()) {
|
||||||
case EQUALS:
|
case AND:
|
||||||
case NOT_EQUALS:
|
case OR:
|
||||||
case LESS:
|
resultExpr = expr;
|
||||||
case LESS_OR_EQUALS:
|
|
||||||
case GREATER:
|
|
||||||
case GREATER_OR_EQUALS: {
|
|
||||||
BinaryExpr comparison = (BinaryExpr) p;
|
|
||||||
Expr result = BinaryExpr.binary(expr.getOperation(), comparison.getType(),
|
|
||||||
comparison.getFirstOperand(), comparison.getSecondOperand());
|
|
||||||
result.setLocation(comparison.getLocation());
|
|
||||||
if (invert) {
|
|
||||||
result = ExprOptimizer.invert(result);
|
|
||||||
}
|
|
||||||
resultExpr = result;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
expr.getSecondOperand().acceptVisitor(this);
|
||||||
|
Expr b = resultExpr;
|
||||||
|
if (b instanceof ConstantExpr && expr.getOperation() == BinaryOperation.SUBTRACT) {
|
||||||
|
if (tryMakePositive((ConstantExpr) b)) {
|
||||||
|
expr.setOperation(BinaryOperation.ADD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expr.getFirstOperand().acceptVisitor(this);
|
||||||
|
Expr a = resultExpr;
|
||||||
|
Expr p = a;
|
||||||
|
Expr q = b;
|
||||||
|
boolean invert = false;
|
||||||
|
if (isZero(p)) {
|
||||||
|
Expr tmp = p;
|
||||||
|
p = q;
|
||||||
|
q = tmp;
|
||||||
|
invert = true;
|
||||||
|
}
|
||||||
|
if (isComparison(p) && isZero(q)) {
|
||||||
|
switch (expr.getOperation()) {
|
||||||
|
case EQUALS:
|
||||||
|
case NOT_EQUALS:
|
||||||
|
case LESS:
|
||||||
|
case LESS_OR_EQUALS:
|
||||||
|
case GREATER:
|
||||||
|
case GREATER_OR_EQUALS: {
|
||||||
|
BinaryExpr comparison = (BinaryExpr) p;
|
||||||
|
Expr result = BinaryExpr.binary(expr.getOperation(), comparison.getType(),
|
||||||
|
comparison.getFirstOperand(), comparison.getSecondOperand());
|
||||||
|
result.setLocation(comparison.getLocation());
|
||||||
|
if (invert) {
|
||||||
|
result = ExprOptimizer.invert(result);
|
||||||
|
}
|
||||||
|
resultExpr = result;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expr.setFirstOperand(a);
|
||||||
|
expr.setSecondOperand(b);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
expr.setFirstOperand(a);
|
|
||||||
expr.setSecondOperand(b);
|
|
||||||
resultExpr = expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(UnaryExpr expr) {
|
public void visit(UnaryExpr expr) {
|
||||||
expr.getOperand().acceptVisitor(this);
|
pushLocation(expr.getLocation());
|
||||||
Expr operand = resultExpr;
|
try {
|
||||||
if (expr.getOperation() == UnaryOperation.NEGATE && operand instanceof ConstantExpr) {
|
expr.getOperand().acceptVisitor(this);
|
||||||
ConstantExpr constantExpr = (ConstantExpr) operand;
|
Expr operand = resultExpr;
|
||||||
if (tryMakePositive(constantExpr)) {
|
if (expr.getOperation() == UnaryOperation.NEGATE && operand instanceof ConstantExpr) {
|
||||||
resultExpr = expr;
|
ConstantExpr constantExpr = (ConstantExpr) operand;
|
||||||
return;
|
if (tryMakePositive(constantExpr)) {
|
||||||
|
resultExpr = expr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
expr.setOperand(operand);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
expr.setOperand(operand);
|
|
||||||
resultExpr = expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean tryMakePositive(ConstantExpr constantExpr) {
|
private boolean tryMakePositive(ConstantExpr constantExpr) {
|
||||||
|
@ -177,16 +213,21 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConditionalExpr expr) {
|
public void visit(ConditionalExpr expr) {
|
||||||
expr.getCondition().acceptVisitor(this);
|
pushLocation(expr.getLocation());
|
||||||
Expr cond = resultExpr;
|
try {
|
||||||
expr.getConsequent().acceptVisitor(this);
|
expr.getCondition().acceptVisitor(this);
|
||||||
Expr consequent = resultExpr;
|
Expr cond = resultExpr;
|
||||||
expr.getAlternative().acceptVisitor(this);
|
expr.getConsequent().acceptVisitor(this);
|
||||||
Expr alternative = resultExpr;
|
Expr consequent = resultExpr;
|
||||||
expr.setCondition(cond);
|
expr.getAlternative().acceptVisitor(this);
|
||||||
expr.setConsequent(consequent);
|
Expr alternative = resultExpr;
|
||||||
expr.setAlternative(alternative);
|
expr.setCondition(cond);
|
||||||
resultExpr = expr;
|
expr.setConsequent(consequent);
|
||||||
|
expr.setAlternative(alternative);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -196,70 +237,92 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(VariableExpr expr) {
|
public void visit(VariableExpr expr) {
|
||||||
int index = expr.getIndex();
|
pushLocation(expr.getLocation());
|
||||||
resultExpr = expr;
|
try {
|
||||||
if (writeFrequencies[index] != 1) {
|
int index = expr.getIndex();
|
||||||
return;
|
resultExpr = expr;
|
||||||
}
|
if (writeFrequencies[index] != 1) {
|
||||||
if (readFrequencies[index] != 1 || preservedVars[index]) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (readFrequencies[index] != 1 || preservedVars[index]) {
|
||||||
if (resultSequence.isEmpty()) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (resultSequence.isEmpty()) {
|
||||||
Statement last = resultSequence.get(resultSequence.size() - 1);
|
return;
|
||||||
if (!(last instanceof AssignmentStatement)) {
|
}
|
||||||
return;
|
Statement last = resultSequence.get(resultSequence.size() - 1);
|
||||||
}
|
if (!(last instanceof AssignmentStatement)) {
|
||||||
AssignmentStatement assignment = (AssignmentStatement) last;
|
return;
|
||||||
if (assignment.isAsync()) {
|
}
|
||||||
return;
|
AssignmentStatement assignment = (AssignmentStatement) last;
|
||||||
}
|
if (assignment.isAsync()) {
|
||||||
if (!(assignment.getLeftValue() instanceof VariableExpr)) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (!(assignment.getLeftValue() instanceof VariableExpr)) {
|
||||||
VariableExpr var = (VariableExpr) assignment.getLeftValue();
|
return;
|
||||||
if (var.getLocation() != null && assignment.getLocation() != null
|
}
|
||||||
&& !assignment.getLocation().equals(var.getLocation())) {
|
VariableExpr var = (VariableExpr) assignment.getLeftValue();
|
||||||
return;
|
if (friendlyToDebugger) {
|
||||||
}
|
if (currentLocation != null && assignment.getLocation() != null
|
||||||
if (var.getIndex() == index) {
|
&& !assignment.getLocation().equals(currentLocation)) {
|
||||||
resultSequence.remove(resultSequence.size() - 1);
|
return;
|
||||||
assignment.getRightValue().setLocation(assignment.getLocation());
|
}
|
||||||
assignment.getRightValue().acceptVisitor(this);
|
}
|
||||||
|
if (var.getIndex() == index) {
|
||||||
|
resultSequence.remove(resultSequence.size() - 1);
|
||||||
|
assignment.getRightValue().setLocation(assignment.getLocation());
|
||||||
|
assignment.getRightValue().acceptVisitor(this);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SubscriptExpr expr) {
|
public void visit(SubscriptExpr expr) {
|
||||||
expr.getIndex().acceptVisitor(this);
|
pushLocation(expr.getLocation());
|
||||||
Expr index = resultExpr;
|
try {
|
||||||
expr.getArray().acceptVisitor(this);
|
expr.getIndex().acceptVisitor(this);
|
||||||
Expr array = resultExpr;
|
Expr index = resultExpr;
|
||||||
expr.setArray(array);
|
expr.getArray().acceptVisitor(this);
|
||||||
expr.setIndex(index);
|
Expr array = resultExpr;
|
||||||
resultExpr = expr;
|
expr.setArray(array);
|
||||||
|
expr.setIndex(index);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(UnwrapArrayExpr expr) {
|
public void visit(UnwrapArrayExpr expr) {
|
||||||
expr.getArray().acceptVisitor(this);
|
pushLocation(expr.getLocation());
|
||||||
Expr arrayExpr = resultExpr;
|
try {
|
||||||
expr.setArray(arrayExpr);
|
expr.getArray().acceptVisitor(this);
|
||||||
resultExpr = expr;
|
Expr arrayExpr = resultExpr;
|
||||||
|
expr.setArray(arrayExpr);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InvocationExpr expr) {
|
public void visit(InvocationExpr expr) {
|
||||||
Expr[] args = new Expr[expr.getArguments().size()];
|
pushLocation(expr.getLocation());
|
||||||
for (int i = expr.getArguments().size() - 1; i >= 0; --i) {
|
try {
|
||||||
expr.getArguments().get(i).acceptVisitor(this);
|
Expr[] args = new Expr[expr.getArguments().size()];
|
||||||
args[i] = resultExpr;
|
for (int i = expr.getArguments().size() - 1; i >= 0; --i) {
|
||||||
|
expr.getArguments().get(i).acceptVisitor(this);
|
||||||
|
args[i] = resultExpr;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < args.length; ++i) {
|
||||||
|
expr.getArguments().set(i, args[i]);
|
||||||
|
}
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < args.length; ++i) {
|
|
||||||
expr.getArguments().set(i, args[i]);
|
|
||||||
}
|
|
||||||
resultExpr = expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean tryApplyConstructor(InvocationExpr expr) {
|
private boolean tryApplyConstructor(InvocationExpr expr) {
|
||||||
|
@ -303,12 +366,17 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(QualificationExpr expr) {
|
public void visit(QualificationExpr expr) {
|
||||||
if (expr.getQualified() != null) {
|
pushLocation(expr.getLocation());
|
||||||
expr.getQualified().acceptVisitor(this);
|
try {
|
||||||
Expr qualified = resultExpr;
|
if (expr.getQualified() != null) {
|
||||||
expr.setQualified(qualified);
|
expr.getQualified().acceptVisitor(this);
|
||||||
|
Expr qualified = resultExpr;
|
||||||
|
expr.setQualified(qualified);
|
||||||
|
}
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
resultExpr = expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -318,64 +386,94 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NewArrayExpr expr) {
|
public void visit(NewArrayExpr expr) {
|
||||||
expr.getLength().acceptVisitor(this);
|
pushLocation(expr.getLocation());
|
||||||
Expr length = resultExpr;
|
try {
|
||||||
expr.setLength(length);
|
expr.getLength().acceptVisitor(this);
|
||||||
resultExpr = expr;
|
Expr length = resultExpr;
|
||||||
|
expr.setLength(length);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NewMultiArrayExpr expr) {
|
public void visit(NewMultiArrayExpr expr) {
|
||||||
for (int i = 0; i < expr.getDimensions().size(); ++i) {
|
pushLocation(expr.getLocation());
|
||||||
Expr dimension = expr.getDimensions().get(i);
|
try {
|
||||||
dimension.acceptVisitor(this);
|
for (int i = 0; i < expr.getDimensions().size(); ++i) {
|
||||||
expr.getDimensions().set(i, resultExpr);
|
Expr dimension = expr.getDimensions().get(i);
|
||||||
|
dimension.acceptVisitor(this);
|
||||||
|
expr.getDimensions().set(i, resultExpr);
|
||||||
|
}
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
resultExpr = expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InstanceOfExpr expr) {
|
public void visit(InstanceOfExpr expr) {
|
||||||
expr.getExpr().acceptVisitor(this);
|
pushLocation(expr.getLocation());
|
||||||
expr.setExpr(resultExpr);
|
try {
|
||||||
resultExpr = expr;
|
expr.getExpr().acceptVisitor(this);
|
||||||
|
expr.setExpr(resultExpr);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CastExpr expr) {
|
public void visit(CastExpr expr) {
|
||||||
expr.getValue().acceptVisitor(this);
|
pushLocation(expr.getLocation());
|
||||||
expr.setValue(resultExpr);
|
try {
|
||||||
resultExpr = expr;
|
expr.getValue().acceptVisitor(this);
|
||||||
|
expr.setValue(resultExpr);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(PrimitiveCastExpr expr) {
|
public void visit(PrimitiveCastExpr expr) {
|
||||||
expr.getValue().acceptVisitor(this);
|
pushLocation(expr.getLocation());
|
||||||
expr.setValue(resultExpr);
|
try {
|
||||||
resultExpr = expr;
|
expr.getValue().acceptVisitor(this);
|
||||||
|
expr.setValue(resultExpr);
|
||||||
|
resultExpr = expr;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(AssignmentStatement statement) {
|
public void visit(AssignmentStatement statement) {
|
||||||
if (statement.getLeftValue() == null) {
|
pushLocation(statement.getLocation());
|
||||||
statement.getRightValue().acceptVisitor(this);
|
try {
|
||||||
if (resultExpr instanceof InvocationExpr && tryApplyConstructor((InvocationExpr) resultExpr)) {
|
if (statement.getLeftValue() == null) {
|
||||||
resultStmt = new SequentialStatement();
|
statement.getRightValue().acceptVisitor(this);
|
||||||
|
if (resultExpr instanceof InvocationExpr && tryApplyConstructor((InvocationExpr) resultExpr)) {
|
||||||
|
resultStmt = new SequentialStatement();
|
||||||
|
} else {
|
||||||
|
statement.setRightValue(resultExpr);
|
||||||
|
resultStmt = statement;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
statement.setRightValue(resultExpr);
|
statement.getRightValue().acceptVisitor(this);
|
||||||
|
Expr right = resultExpr;
|
||||||
|
Expr left = statement.getLeftValue();
|
||||||
|
if (!(statement.getLeftValue() instanceof VariableExpr)) {
|
||||||
|
statement.getLeftValue().acceptVisitor(this);
|
||||||
|
left = resultExpr;
|
||||||
|
}
|
||||||
|
statement.setLeftValue(left);
|
||||||
|
statement.setRightValue(right);
|
||||||
resultStmt = statement;
|
resultStmt = statement;
|
||||||
}
|
}
|
||||||
} else {
|
} finally {
|
||||||
statement.getRightValue().acceptVisitor(this);
|
popLocation();
|
||||||
Expr right = resultExpr;
|
|
||||||
Expr left = statement.getLeftValue();
|
|
||||||
if (!(statement.getLeftValue() instanceof VariableExpr)) {
|
|
||||||
statement.getLeftValue().acceptVisitor(this);
|
|
||||||
left = resultExpr;
|
|
||||||
}
|
|
||||||
statement.setLeftValue(left);
|
|
||||||
statement.setRightValue(right);
|
|
||||||
resultStmt = statement;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,23 +822,38 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ReturnStatement statement) {
|
public void visit(ReturnStatement statement) {
|
||||||
if (statement.getResult() != null) {
|
pushLocation(statement.getLocation());
|
||||||
statement.getResult().acceptVisitor(this);
|
try {
|
||||||
statement.setResult(resultExpr);
|
if (statement.getResult() != null) {
|
||||||
|
statement.getResult().acceptVisitor(this);
|
||||||
|
statement.setResult(resultExpr);
|
||||||
|
}
|
||||||
|
resultStmt = statement;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
}
|
}
|
||||||
resultStmt = statement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ThrowStatement statement) {
|
public void visit(ThrowStatement statement) {
|
||||||
statement.getException().acceptVisitor(this);
|
pushLocation(statement.getLocation());
|
||||||
statement.setException(resultExpr);
|
try {
|
||||||
resultStmt = statement;
|
statement.getException().acceptVisitor(this);
|
||||||
|
statement.setException(resultExpr);
|
||||||
|
resultStmt = statement;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InitClassStatement statement) {
|
public void visit(InitClassStatement statement) {
|
||||||
resultStmt = statement;
|
pushLocation(statement.getLocation());
|
||||||
|
try {
|
||||||
|
resultStmt = statement;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -761,15 +874,25 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorEnterStatement statement) {
|
public void visit(MonitorEnterStatement statement) {
|
||||||
statement.getObjectRef().acceptVisitor(this);
|
pushLocation(statement.getLocation());
|
||||||
statement.setObjectRef(resultExpr);
|
try {
|
||||||
resultStmt = statement;
|
statement.getObjectRef().acceptVisitor(this);
|
||||||
|
statement.setObjectRef(resultExpr);
|
||||||
|
resultStmt = statement;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorExitStatement statement) {
|
public void visit(MonitorExitStatement statement) {
|
||||||
statement.getObjectRef().acceptVisitor(this);
|
pushLocation(statement.getLocation());
|
||||||
statement.setObjectRef(resultExpr);
|
try {
|
||||||
resultStmt = statement;
|
statement.getObjectRef().acceptVisitor(this);
|
||||||
|
statement.setObjectRef(resultExpr);
|
||||||
|
resultStmt = statement;
|
||||||
|
} finally {
|
||||||
|
popLocation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,7 +294,8 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||||
asyncMethods.addAll(asyncFinder.getAsyncMethods());
|
asyncMethods.addAll(asyncFinder.getAsyncMethods());
|
||||||
asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods());
|
asyncFamilyMethods.addAll(asyncFinder.getAsyncFamilyMethods());
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), asyncMethods, asyncFamilyMethods);
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), asyncMethods, asyncFamilyMethods,
|
||||||
|
controller.isFriendlyToDebugger());
|
||||||
decompiler.setRegularMethodCache(controller.isIncremental() ? astCache : null);
|
decompiler.setRegularMethodCache(controller.isIncremental() ? astCache : null);
|
||||||
|
|
||||||
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {
|
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {
|
||||||
|
|
|
@ -926,7 +926,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (expr.getLocation() != null) {
|
if (expr.getLocation() != null) {
|
||||||
pushLocation(expr.getLocation());
|
popLocation();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error occured", e);
|
throw new RenderingException("IO error occured", e);
|
||||||
|
|
|
@ -291,7 +291,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
||||||
classes, vtableProvider, tagRegistry, binaryWriter);
|
classes, vtableProvider, tagRegistry, binaryWriter);
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||||
new HashSet<>());
|
new HashSet<>(), false);
|
||||||
WasmStringPool stringPool = classGenerator.getStringPool();
|
WasmStringPool stringPool = classGenerator.getStringPool();
|
||||||
WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
||||||
vtableProvider, tagRegistry, stringPool);
|
vtableProvider, tagRegistry, stringPool);
|
||||||
|
|
|
@ -34,8 +34,8 @@ public class Debugger {
|
||||||
private ConcurrentMap<String, ConcurrentMap<DebugInformation, Object>> debugInformationFileMap =
|
private ConcurrentMap<String, ConcurrentMap<DebugInformation, Object>> debugInformationFileMap =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
private ConcurrentMap<DebugInformation, String> scriptMap = new ConcurrentHashMap<>();
|
private ConcurrentMap<DebugInformation, String> scriptMap = new ConcurrentHashMap<>();
|
||||||
final ConcurrentMap<JavaScriptBreakpoint, Breakpoint> breakpointMap = new ConcurrentHashMap<>();
|
private final ConcurrentMap<JavaScriptBreakpoint, Breakpoint> breakpointMap = new ConcurrentHashMap<>();
|
||||||
ConcurrentMap<Breakpoint, Object> breakpoints = new ConcurrentHashMap<>();
|
private final ConcurrentMap<Breakpoint, Object> breakpoints = new ConcurrentHashMap<>();
|
||||||
private volatile CallFrame[] callStack;
|
private volatile CallFrame[] callStack;
|
||||||
|
|
||||||
public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformationProvider debugInformationProvider) {
|
public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformationProvider debugInformationProvider) {
|
||||||
|
@ -126,12 +126,12 @@ public class Debugger {
|
||||||
javaScriptDebugger.resume();
|
javaScriptDebugger.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CallSiteSuccessorFinder implements DebuggerCallSiteVisitor {
|
static class CallSiteSuccessorFinder implements DebuggerCallSiteVisitor {
|
||||||
private DebugInformation debugInfo;
|
private DebugInformation debugInfo;
|
||||||
private String script;
|
private String script;
|
||||||
Set<JavaScriptLocation> locations;
|
Set<JavaScriptLocation> locations;
|
||||||
|
|
||||||
public CallSiteSuccessorFinder(DebugInformation debugInfo, String script, Set<JavaScriptLocation> locations) {
|
CallSiteSuccessorFinder(DebugInformation debugInfo, String script, Set<JavaScriptLocation> locations) {
|
||||||
this.debugInfo = debugInfo;
|
this.debugInfo = debugInfo;
|
||||||
this.script = script;
|
this.script = script;
|
||||||
this.locations = locations;
|
this.locations = locations;
|
||||||
|
@ -185,7 +185,7 @@ public class Debugger {
|
||||||
|
|
||||||
private List<DebugInformation> debugInformationBySource(String sourceFile) {
|
private List<DebugInformation> debugInformationBySource(String sourceFile) {
|
||||||
Map<DebugInformation, Object> list = debugInformationFileMap.get(sourceFile);
|
Map<DebugInformation, Object> list = debugInformationFileMap.get(sourceFile);
|
||||||
return list != null ? new ArrayList<>(list.keySet()) : Collections.<DebugInformation>emptyList();
|
return list != null ? new ArrayList<>(list.keySet()) : Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void continueToLocation(SourceLocation location) {
|
public void continueToLocation(SourceLocation location) {
|
||||||
|
@ -218,6 +218,10 @@ public class Debugger {
|
||||||
return createBreakpoint(new SourceLocation(file, line));
|
return createBreakpoint(new SourceLocation(file, line));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<? extends String> getSourceFiles() {
|
||||||
|
return debugInformationFileMap.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
public Breakpoint createBreakpoint(SourceLocation location) {
|
public Breakpoint createBreakpoint(SourceLocation location) {
|
||||||
synchronized (breakpointMap) {
|
synchronized (breakpointMap) {
|
||||||
Breakpoint breakpoint = new Breakpoint(this, location);
|
Breakpoint breakpoint = new Breakpoint(this, location);
|
||||||
|
@ -232,7 +236,7 @@ public class Debugger {
|
||||||
return new HashSet<>(breakpoints.keySet());
|
return new HashSet<>(breakpoints.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateInternalBreakpoints(Breakpoint breakpoint) {
|
private void updateInternalBreakpoints(Breakpoint breakpoint) {
|
||||||
if (breakpoint.isDestroyed()) {
|
if (breakpoint.isDestroyed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -259,7 +263,7 @@ public class Debugger {
|
||||||
return listeners.keySet().toArray(new DebuggerListener[0]);
|
return listeners.keySet().toArray(new DebuggerListener[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateBreakpointStatus(Breakpoint breakpoint, boolean fireEvent) {
|
private void updateBreakpointStatus(Breakpoint breakpoint, boolean fireEvent) {
|
||||||
boolean valid = false;
|
boolean valid = false;
|
||||||
for (JavaScriptBreakpoint jsBreakpoint : breakpoint.jsBreakpoints) {
|
for (JavaScriptBreakpoint jsBreakpoint : breakpoint.jsBreakpoints) {
|
||||||
if (jsBreakpoint.isValid()) {
|
if (jsBreakpoint.isValid()) {
|
||||||
|
|
|
@ -63,6 +63,9 @@ class VariableMap extends AbstractMap<String, Variable> {
|
||||||
String[] names = debugger.mapVariable(entry.getKey(), location);
|
String[] names = debugger.mapVariable(entry.getKey(), location);
|
||||||
Value value = new Value(debugger, jsVar.getValue());
|
Value value = new Value(debugger, jsVar.getValue());
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
|
if (name == null) {
|
||||||
|
name = "js:" + jsVar.getName();
|
||||||
|
}
|
||||||
vars.put(name, new Variable(name, value));
|
vars.put(name, new Variable(name, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,7 +216,7 @@ public class DebugInformation {
|
||||||
int[] valueIndexes = mapping.get(keyIndex).getArray(0);
|
int[] valueIndexes = mapping.get(keyIndex).getArray(0);
|
||||||
String[] result = new String[valueIndexes.length];
|
String[] result = new String[valueIndexes.length];
|
||||||
for (int i = 0; i < result.length; ++i) {
|
for (int i = 0; i < result.length; ++i) {
|
||||||
result[i] = variableNames[valueIndexes[i]];
|
result[i] = valueIndexes[i] >= 0 ? variableNames[valueIndexes[i]] : null;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
if (lastRecord.get(0) == locationProvider.getLine() && lastRecord.get(1) == locationProvider.getColumn()) {
|
if (lastRecord.get(0) == locationProvider.getLine() && lastRecord.get(1) == locationProvider.getColumn()) {
|
||||||
|
@ -132,11 +132,8 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
||||||
}
|
}
|
||||||
Arrays.sort(sourceIndexes);
|
Arrays.sort(sourceIndexes);
|
||||||
int generatedIndex = variableNames.index(generatedName);
|
int generatedIndex = variableNames.index(generatedName);
|
||||||
RecordArrayBuilder mapping = variableMappings.get(generatedIndex);
|
RecordArrayBuilder mapping = variableMappings.computeIfAbsent(generatedIndex,
|
||||||
if (mapping == null) {
|
k -> new RecordArrayBuilder(2, 1));
|
||||||
mapping = new RecordArrayBuilder(2, 1);
|
|
||||||
variableMappings.put(generatedIndex, mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordArrayBuilder.Record record = add(mapping);
|
RecordArrayBuilder.Record record = add(mapping);
|
||||||
RecordArrayBuilder.SubArray array = record.getArray(0);
|
RecordArrayBuilder.SubArray array = record.getArray(0);
|
||||||
|
|
|
@ -661,5 +661,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
public Map<String, String> getExportedClasses() {
|
public Map<String, String> getExportedClasses() {
|
||||||
return readonlyExportedClasses;
|
return readonlyExportedClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFriendlyToDebugger() {
|
||||||
|
return optimizationLevel == TeaVMOptimizationLevel.SIMPLE;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,8 @@ public interface TeaVMTargetController {
|
||||||
|
|
||||||
boolean isIncremental();
|
boolean isIncremental();
|
||||||
|
|
||||||
|
boolean isFriendlyToDebugger();
|
||||||
|
|
||||||
Map<String, TeaVMEntryPoint> getEntryPoints();
|
Map<String, TeaVMEntryPoint> getEntryPoints();
|
||||||
|
|
||||||
Map<String, String> getExportedClasses();
|
Map<String, String> getExportedClasses();
|
||||||
|
|
|
@ -24,6 +24,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
@ -119,7 +121,12 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CompletableFuture<Object> future = futures.remove(response.getId());
|
CompletableFuture<Object> future = futures.remove(response.getId());
|
||||||
responseHandlers.remove(response.getId()).received(response.getResult(), future);
|
try {
|
||||||
|
responseHandlers.remove(response.getId()).received(response.getResult(), future);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.warn("Error processing message ${}", response.getId(), e);
|
||||||
|
future.completeExceptionally(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Message message = mapper.reader(Message.class).readValue(messageText);
|
Message message = mapper.reader(Message.class).readValue(messageText);
|
||||||
if (message.getMethod() == null) {
|
if (message.getMethod() == null) {
|
||||||
|
@ -386,7 +393,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return read(sync);
|
return read(sync);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException | TimeoutException e) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,6 +428,8 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
return result.isEmpty() ? null : result;
|
return result.isEmpty() ? null : result;
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
return null;
|
return null;
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
return "<timed out>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,6 +463,8 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
return result.repr;
|
return result.repr;
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
return null;
|
return null;
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
return "<timed out>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,9 +570,9 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
||||||
void received(JsonNode node, CompletableFuture<T> out) throws IOException;
|
void received(JsonNode node, CompletableFuture<T> out) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> T read(Future<T> future) throws InterruptedException {
|
private static <T> T read(Future<T> future) throws InterruptedException, TimeoutException {
|
||||||
try {
|
try {
|
||||||
return future.get();
|
return future.get(1500, TimeUnit.MILLISECONDS);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
Throwable cause = e.getCause();
|
Throwable cause = e.getCause();
|
||||||
if (cause instanceof RuntimeException) {
|
if (cause instanceof RuntimeException) {
|
||||||
|
|
|
@ -51,6 +51,11 @@ public final class ChromeRDPRunner {
|
||||||
new Thread(server::start).start();
|
new Thread(server::start).start();
|
||||||
debugger = new Debugger(jsDebugger, new URLDebugInformationProvider(""));
|
debugger = new Debugger(jsDebugger, new URLDebugInformationProvider(""));
|
||||||
debugger.addListener(listener);
|
debugger.addListener(listener);
|
||||||
|
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
||||||
|
System.err.println("Uncaught exception in thread " + t);
|
||||||
|
e.printStackTrace();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private DebuggerListener listener = new DebuggerListener() {
|
private DebuggerListener listener = new DebuggerListener() {
|
||||||
|
@ -221,12 +226,55 @@ public final class ChromeRDPRunner {
|
||||||
System.out.println("Expected 2 arguments");
|
System.out.println("Expected 2 arguments");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Breakpoint bp = debugger.createBreakpoint(args[1], Integer.parseInt(args[2]));
|
|
||||||
|
String[] fileNames = resolveFileName(args[1]);
|
||||||
|
if (fileNames.length == 0) {
|
||||||
|
System.out.println("Unknown file: " + args[1]);
|
||||||
|
return;
|
||||||
|
} else if (fileNames.length > 1) {
|
||||||
|
System.out.println("Ambiguous file name: " + args[1] + ". Possible names are: "
|
||||||
|
+ Arrays.toString(fileNames));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Breakpoint bp = debugger.createBreakpoint(fileNames[0], Integer.parseInt(args[2]));
|
||||||
int id = breakpointIdGen++;
|
int id = breakpointIdGen++;
|
||||||
breakpointIds.put(bp, id);
|
breakpointIds.put(bp, id);
|
||||||
System.out.println("Breakpoint #" + id + " was set at " + bp.getLocation());
|
System.out.println("Breakpoint #" + id + " was set at " + bp.getLocation());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private String[] resolveFileName(String fileName) {
|
||||||
|
if (debugger.getSourceFiles().contains(fileName)) {
|
||||||
|
return new String[] { fileName };
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] result = debugger.getSourceFiles().stream()
|
||||||
|
.filter(f -> f.endsWith(fileName) && isPrecededByPathSeparator(f, fileName))
|
||||||
|
.toArray(String[]::new);
|
||||||
|
if (result.length == 1) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return debugger.getSourceFiles().stream()
|
||||||
|
.filter(f -> {
|
||||||
|
int index = f.lastIndexOf('.');
|
||||||
|
if (index <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String nameWithoutExt = f.substring(0, index);
|
||||||
|
return nameWithoutExt.endsWith(fileName) && isPrecededByPathSeparator(nameWithoutExt, fileName);
|
||||||
|
})
|
||||||
|
.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPrecededByPathSeparator(String actualName, String specifiedName) {
|
||||||
|
if (actualName.length() < specifiedName.length() + 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char c = actualName.charAt(actualName.length() - specifiedName.length() - 1);
|
||||||
|
return c == '/' || c == '\\';
|
||||||
|
}
|
||||||
|
|
||||||
private Command backtraceCommand = args -> {
|
private Command backtraceCommand = args -> {
|
||||||
CallFrame[] callStack = debugger.getCallStack();
|
CallFrame[] callStack = debugger.getCallStack();
|
||||||
for (int i = 0; i < callStack.length; ++i) {
|
for (int i = 0; i < callStack.length; ++i) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user