Propagating variable name via compiler's pipeline

This commit is contained in:
Alexey Andreev 2016-08-25 23:36:28 +03:00
parent c5c453d95b
commit 1c1b0c69fa
29 changed files with 202 additions and 187 deletions

View File

@ -49,7 +49,7 @@ public final class TArray extends TObject {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static RuntimeObject newInstanceLowLevel(RuntimeClass cls, int length) { private static RuntimeObject newInstanceLowLevel(RuntimeClass cls, int length) {
return Allocator.allocateArray(cls, length).toStructure(); return Allocator.allocateArray(cls.arrayType, length).toStructure();
} }
public static TObject get(TObject array, int index) throws TIllegalArgumentException, public static TObject get(TObject array, int index) throws TIllegalArgumentException,

View File

@ -15,15 +15,12 @@
*/ */
package org.teavm.ast; package org.teavm.ast;
import java.util.HashSet;
import java.util.Set;
import org.teavm.model.TextLocation; import org.teavm.model.TextLocation;
public class AssignmentStatement extends Statement { public class AssignmentStatement extends Statement {
private Expr leftValue; private Expr leftValue;
private Expr rightValue; private Expr rightValue;
private TextLocation location; private TextLocation location;
private Set<String> debugNames = new HashSet<>();
private boolean async; private boolean async;
public Expr getLeftValue() { public Expr getLeftValue() {
@ -50,10 +47,6 @@ public class AssignmentStatement extends Statement {
this.location = location; this.location = location;
} }
public Set<String> getDebugNames() {
return debugNames;
}
public boolean isAsync() { public boolean isAsync() {
return async; return async;
} }

View File

@ -17,8 +17,6 @@ package org.teavm.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
public class AsyncMethodNode extends MethodNode { public class AsyncMethodNode extends MethodNode {
@ -33,19 +31,11 @@ public class AsyncMethodNode extends MethodNode {
return body; return body;
} }
@Override
public List<VariableNode> getVariables() { public List<VariableNode> getVariables() {
return variables; return variables;
} }
@Override
public List<Set<String>> getParameterDebugNames() {
return variables.subList(0, getReference().parameterCount())
.stream()
.map(VariableNode::getDebugNames)
.collect(Collectors.toList());
}
@Override @Override
public void acceptVisitor(MethodNodeVisitor visitor) { public void acceptVisitor(MethodNodeVisitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -42,5 +42,5 @@ public abstract class MethodNode {
public abstract boolean isAsync(); public abstract boolean isAsync();
public abstract List<Set<String>> getParameterDebugNames(); public abstract List<VariableNode> getVariables();
} }

View File

@ -17,7 +17,6 @@ package org.teavm.ast;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
import org.teavm.backend.javascript.spi.Generator; import org.teavm.backend.javascript.spi.Generator;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -52,7 +51,7 @@ public class NativeMethodNode extends MethodNode {
} }
@Override @Override
public List<Set<String>> getParameterDebugNames() { public List<VariableNode> getVariables() {
return Collections.emptyList(); return Collections.emptyList();
} }
} }

View File

@ -17,8 +17,6 @@ package org.teavm.ast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
public class RegularMethodNode extends MethodNode { public class RegularMethodNode extends MethodNode {
@ -37,18 +35,11 @@ public class RegularMethodNode extends MethodNode {
this.body = body; this.body = body;
} }
@Override
public List<VariableNode> getVariables() { public List<VariableNode> getVariables() {
return variables; return variables;
} }
@Override
public List<Set<String>> getParameterDebugNames() {
return variables.subList(0, getReference().parameterCount())
.stream()
.map(VariableNode::getDebugNames)
.collect(Collectors.toList());
}
@Override @Override
public void acceptVisitor(MethodNodeVisitor visitor) { public void acceptVisitor(MethodNodeVisitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -15,14 +15,12 @@
*/ */
package org.teavm.ast; package org.teavm.ast;
import java.util.HashSet;
import java.util.Set;
import org.teavm.model.util.VariableType; import org.teavm.model.util.VariableType;
public class VariableNode { public class VariableNode {
private int index; private int index;
private VariableType type; private VariableType type;
private Set<String> debugNames = new HashSet<>(); private String name;
public VariableNode(int index, VariableType type) { public VariableNode(int index, VariableType type) {
this.index = index; this.index = index;
@ -45,7 +43,11 @@ public class VariableNode {
this.type = type; this.type = type;
} }
public Set<String> getDebugNames() { public String getName() {
return debugNames; return name;
}
public void setName(String name) {
this.name = name;
} }
} }

View File

@ -65,7 +65,6 @@ import org.teavm.model.Program;
import org.teavm.model.TextLocation; import org.teavm.model.TextLocation;
import org.teavm.model.TryCatchBlock; import org.teavm.model.TryCatchBlock;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.util.AsyncProgramSplitter; import org.teavm.model.util.AsyncProgramSplitter;
import org.teavm.model.util.ListingBuilder; import org.teavm.model.util.ListingBuilder;
import org.teavm.model.util.ProgramUtils; import org.teavm.model.util.ProgramUtils;
@ -271,17 +270,14 @@ public class Decompiler {
typeInferer.inferTypes(program, method.getReference()); typeInferer.inferTypes(program, method.getReference());
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
VariableNode variable = new VariableNode(program.variableAt(i).getRegister(), typeInferer.typeOf(i)); VariableNode variable = new VariableNode(program.variableAt(i).getRegister(), typeInferer.typeOf(i));
variable.setName(program.variableAt(i).getDebugName());
methodNode.getVariables().add(variable); methodNode.getVariables().add(variable);
} }
Optimizer optimizer = new Optimizer(); Optimizer optimizer = new Optimizer();
optimizer.optimize(methodNode, method.getProgram()); optimizer.optimize(methodNode, method.getProgram());
methodNode.getModifiers().addAll(method.getModifiers()); methodNode.getModifiers().addAll(method.getModifiers());
int paramCount = Math.min(method.getSignature().length, program.variableCount());
for (int i = 0; i < paramCount; ++i) {
Variable var = program.variableAt(i);
methodNode.getParameterDebugNames().add(new HashSet<>(var.getDebugNames()));
}
return methodNode; return methodNode;
} }
@ -338,17 +334,14 @@ public class Decompiler {
typeInferer.inferTypes(program, method.getReference()); typeInferer.inferTypes(program, method.getReference());
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
VariableNode variable = new VariableNode(program.variableAt(i).getRegister(), typeInferer.typeOf(i)); VariableNode variable = new VariableNode(program.variableAt(i).getRegister(), typeInferer.typeOf(i));
variable.setName(program.variableAt(i).getDebugName());
node.getVariables().add(variable); node.getVariables().add(variable);
} }
Optimizer optimizer = new Optimizer(); Optimizer optimizer = new Optimizer();
optimizer.optimize(node, splitter); optimizer.optimize(node, splitter);
node.getModifiers().addAll(method.getModifiers()); node.getModifiers().addAll(method.getModifiers());
int paramCount = Math.min(method.getSignature().length, program.variableCount());
for (int i = 0; i < paramCount; ++i) {
Variable var = program.variableAt(i);
node.getParameterDebugNames().add(new HashSet<>(var.getDebugNames()));
}
return node; return node;
} }

View File

@ -202,7 +202,6 @@ class StatementGenerator implements InstructionVisitor {
public void visit(AssignInstruction insn) { public void visit(AssignInstruction insn) {
AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()),
Expr.var(insn.getAssignee().getIndex())); Expr.var(insn.getAssignee().getIndex()));
stmt.getDebugNames().addAll(insn.getReceiver().getDebugNames());
stmt.setLocation(currentLocation); stmt.setLocation(currentLocation);
statements.add(stmt); statements.add(stmt);
} }
@ -500,7 +499,6 @@ class StatementGenerator implements InstructionVisitor {
AssignmentStatement stmt; AssignmentStatement stmt;
if (insn.getReceiver() != null) { if (insn.getReceiver() != null) {
stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), invocationExpr); stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), invocationExpr);
stmt.getDebugNames().addAll(insn.getReceiver().getDebugNames());
} else { } else {
stmt = Statement.assign(null, invocationExpr); stmt = Statement.assign(null, invocationExpr);
} }
@ -523,7 +521,6 @@ class StatementGenerator implements InstructionVisitor {
private void assign(Expr source, Variable target) { private void assign(Expr source, Variable target) {
AssignmentStatement stmt = Statement.assign(Expr.var(target.getIndex()), source); AssignmentStatement stmt = Statement.assign(Expr.var(target.getIndex()), source);
stmt.setLocation(currentLocation); stmt.setLocation(currentLocation);
stmt.getDebugNames().addAll(target.getDebugNames());
statements.add(stmt); statements.add(stmt);
} }

View File

@ -126,8 +126,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
private boolean async; private boolean async;
private Precedence precedence; private Precedence precedence;
private final Map<String, String> blockIdMap = new HashMap<>(); private final Map<String, String> blockIdMap = new HashMap<>();
private final List<Set<String>> debugNames = new ArrayList<>();
private final List<String> cachedVariableNames = new ArrayList<>(); private final List<String> cachedVariableNames = new ArrayList<>();
private MethodNode currentMethod;
private boolean end; private boolean end;
private int currentPart; private int currentPart;
private List<PostponedFieldInitializer> postponedFieldInitializers = new ArrayList<>(); private List<PostponedFieldInitializer> postponedFieldInitializers = new ArrayList<>();
@ -652,9 +652,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
} }
private void renderBody(MethodNode method, boolean inner) throws IOException { private void renderBody(MethodNode method, boolean inner) throws IOException {
debugNames.clear(); currentMethod = method;
cachedVariableNames.clear(); cachedVariableNames.clear();
debugNames.addAll(method.getParameterDebugNames());
blockIdMap.clear(); blockIdMap.clear();
MethodReference ref = method.getReference(); MethodReference ref = method.getReference();
debugEmitter.emitMethod(ref.getDescriptor()); debugEmitter.emitMethod(ref.getDescriptor());
@ -704,8 +703,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
Renderer.this.async = false; Renderer.this.async = false;
this.async = false; this.async = false;
MethodReference ref = method.getReference(); MethodReference ref = method.getReference();
for (int i = 0; i < method.getParameterDebugNames().size(); ++i) { for (int i = 0; i < method.getVariables().size(); ++i) {
debugEmitter.emitVariable(method.getParameterDebugNames().get(i).toArray(new String[0]), debugEmitter.emitVariable(new String[] { method.getVariables().get(i).getName() },
variableName(i)); variableName(i));
} }
@ -748,8 +747,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
Renderer.this.async = true; Renderer.this.async = true;
this.async = true; this.async = true;
MethodReference ref = methodNode.getReference(); MethodReference ref = methodNode.getReference();
for (int i = 0; i < methodNode.getParameterDebugNames().size(); ++i) { for (int i = 0; i < methodNode.getVariables().size(); ++i) {
debugEmitter.emitVariable(methodNode.getParameterDebugNames().get(i).toArray(new String[0]), debugEmitter.emitVariable(new String[] { methodNode.getVariables().get(i).getName() },
variableName(i)); variableName(i));
} }
int variableCount = 0; int variableCount = 0;
@ -967,11 +966,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (statement.getLocation() != null) { if (statement.getLocation() != null) {
popLocation(); popLocation();
} }
if (statement.getLeftValue() instanceof VariableExpr) {
VariableExpr receiver = (VariableExpr) statement.getLeftValue();
debugEmitter.emitVariable(statement.getDebugNames().toArray(new String[0]),
variableName(receiver.getIndex()));
}
} catch (IOException e) { } catch (IOException e) {
throw new RenderingException("IO error occurred", e); throw new RenderingException("IO error occurred", e);
} }
@ -1258,7 +1252,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
return minifying ? "$t" : "$this"; return minifying ? "$t" : "$this";
} }
Set<String> names = index < debugNames.size() ? debugNames.get(index) : null;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
--index; --index;
if (index < variableNames.length()) { if (index < variableNames.length()) {
@ -1267,11 +1260,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
sb.append(Character.toString(variableNames.charAt(index % variableNames.length())) sb.append(Character.toString(variableNames.charAt(index % variableNames.length()))
+ index / variableNames.length()); + index / variableNames.length());
} }
if (!minifying && names != null && !names.isEmpty()) { if (!minifying) {
List<String> nameList = new ArrayList<>(names); VariableNode variable = index < currentMethod.getVariables().size()
Collections.sort(nameList); ? currentMethod.getVariables().get(index)
for (String name : nameList) { : null;
sb.append('_').append(escapeName(name)); if (variable != null && variable.getName() != null) {
sb.setLength(0);
sb.append(escapeName(variable.getName()));
} }
} }
return sb.toString(); return sb.toString();

View File

@ -65,7 +65,7 @@ public class WasmGenerator {
WasmType type = variable.getType() != null WasmType type = variable.getType() != null
? WasmGeneratorUtil.mapType(variable.getType()) ? WasmGeneratorUtil.mapType(variable.getType())
: WasmType.INT32; : WasmType.INT32;
function.add(new WasmLocal(type)); function.add(new WasmLocal(type, variable.getName()));
} }
for (int i = firstVariable; i <= methodReference.parameterCount(); ++i) { for (int i = firstVariable; i <= methodReference.parameterCount(); ++i) {

View File

@ -182,12 +182,16 @@ public class WasmCRenderer {
} }
sb.append(WasmCRenderingVisitor.mapType(function.getResult())).append(' '); sb.append(WasmCRenderingVisitor.mapType(function.getResult())).append(' ');
sb.append(function.getName()).append("("); sb.append(function.getName()).append("(");
WasmCRenderingVisitor visitor = new WasmCRenderingVisitor(function.getResult(), function.getModule());
for (int i = 0; i < function.getParameters().size(); ++i) { for (int i = 0; i < function.getParameters().size(); ++i) {
if (i > 0) { if (i > 0) {
sb.append(", "); sb.append(", ");
} }
sb.append(WasmCRenderingVisitor.mapType(function.getParameters().get(i))); sb.append(WasmCRenderingVisitor.mapType(function.getParameters().get(i)));
sb.append(" var_" + i); WasmLocal local = i < function.getLocalVariables().size()
? function.getLocalVariables().get(i)
: null;
sb.append(" ").append(local != null ? visitor.getVariableName(local) : "var_" + i);
} }
sb.append(")"); sb.append(")");

View File

@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmLocal;
import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBlock;
@ -303,7 +304,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
@Override @Override
public void visit(WasmGetLocal expression) { public void visit(WasmGetLocal expression) {
value = new CExpression("var_" + expression.getLocal().getIndex()); value = new CExpression(getVariableName(expression.getLocal()));
} }
@Override @Override
@ -313,7 +314,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
expression.getValue().acceptVisitor(this); expression.getValue().acceptVisitor(this);
result.getLines().addAll(value.getLines()); result.getLines().addAll(value.getLines());
result.addLine("var_" + expression.getLocal().getIndex() + " = " + value.getText() + ";", result.addLine(getVariableName(expression.getLocal()) + " = " + value.getText() + ";",
expression.getLocation()); expression.getLocation());
value = result; value = result;
@ -1033,4 +1034,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
String temporaryVariable; String temporaryVariable;
WasmType type; WasmType type;
} }
String getVariableName(WasmLocal local) {
if (local.getName() != null) {
return local.getName();
}
return "var_" + local.getIndex();
}
} }

View File

@ -20,7 +20,6 @@ import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -45,7 +44,6 @@ import org.teavm.ast.InitClassStatement;
import org.teavm.ast.InstanceOfExpr; import org.teavm.ast.InstanceOfExpr;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.ast.InvocationType; import org.teavm.ast.InvocationType;
import org.teavm.ast.MethodNode;
import org.teavm.ast.MonitorEnterStatement; import org.teavm.ast.MonitorEnterStatement;
import org.teavm.ast.MonitorExitStatement; import org.teavm.ast.MonitorExitStatement;
import org.teavm.ast.NewArrayExpr; import org.teavm.ast.NewArrayExpr;
@ -99,7 +97,6 @@ public class AstIO {
for (VariableNode var : method.getVariables()) { for (VariableNode var : method.getVariables()) {
write(output, var); write(output, var);
} }
output.writeShort(method.getParameterDebugNames().size());
try { try {
method.getBody().acceptVisitor(new NodeWriter(output)); method.getBody().acceptVisitor(new NodeWriter(output));
} catch (IOExceptionWrapper e) { } catch (IOExceptionWrapper e) {
@ -110,10 +107,7 @@ public class AstIO {
private void write(DataOutput output, VariableNode variable) throws IOException { private void write(DataOutput output, VariableNode variable) throws IOException {
output.writeShort(variable.getIndex()); output.writeShort(variable.getIndex());
output.writeByte(variable.getType().ordinal()); output.writeByte(variable.getType().ordinal());
output.writeByte(variable.getDebugNames().size()); output.writeUTF(variable.getName() != null ? variable.getName() : "");
for (String debugName : variable.getDebugNames()) {
output.writeUTF(debugName);
}
} }
public RegularMethodNode read(DataInput input, MethodReference method) throws IOException { public RegularMethodNode read(DataInput input, MethodReference method) throws IOException {
@ -133,7 +127,10 @@ public class AstIO {
VariableNode variable = new VariableNode(index, type); VariableNode variable = new VariableNode(index, type);
int nameCount = input.readByte(); int nameCount = input.readByte();
for (int i = 0; i < nameCount; ++i) { for (int i = 0; i < nameCount; ++i) {
variable.getDebugNames().add(input.readUTF()); variable.setName(input.readUTF());
if (variable.getName().isEmpty()) {
variable.setName(null);
}
} }
return variable; return variable;
} }
@ -144,8 +141,6 @@ public class AstIO {
for (VariableNode var : method.getVariables()) { for (VariableNode var : method.getVariables()) {
write(output, var); write(output, var);
} }
output.writeShort(method.getParameterDebugNames().size());
writeParameters(output, method);
try { try {
output.writeShort(method.getBody().size()); output.writeShort(method.getBody().size());
for (int i = 0; i < method.getBody().size(); ++i) { for (int i = 0; i < method.getBody().size(); ++i) {
@ -156,17 +151,6 @@ public class AstIO {
} }
} }
private void writeParameters(DataOutput output, MethodNode method) throws IOException {
for (Set<String> debugNames : method.getParameterDebugNames()) {
output.writeShort(debugNames != null ? debugNames.size() : 0);
if (debugNames != null) {
for (String debugName : debugNames) {
output.writeUTF(debugName);
}
}
}
}
public AsyncMethodNode readAsync(DataInput input, MethodReference method) throws IOException { public AsyncMethodNode readAsync(DataInput input, MethodReference method) throws IOException {
AsyncMethodNode node = new AsyncMethodNode(method); AsyncMethodNode node = new AsyncMethodNode(method);
node.getModifiers().addAll(unpackModifiers(input.readInt())); node.getModifiers().addAll(unpackModifiers(input.readInt()));
@ -174,7 +158,6 @@ public class AstIO {
for (int i = 0; i < varCount; ++i) { for (int i = 0; i < varCount; ++i) {
node.getVariables().add(readVariable(input)); node.getVariables().add(readVariable(input));
} }
readParameters(input, node);
int partCount = input.readShort(); int partCount = input.readShort();
for (int i = 0; i < partCount; ++i) { for (int i = 0; i < partCount; ++i) {
AsyncMethodPart part = new AsyncMethodPart(); AsyncMethodPart part = new AsyncMethodPart();
@ -184,18 +167,6 @@ public class AstIO {
return node; return node;
} }
private void readParameters(DataInput input, MethodNode node) throws IOException {
int paramDebugNameCount = input.readShort();
for (int i = 0; i < paramDebugNameCount; ++i) {
int debugNameCount = input.readShort();
Set<String> debugNames = new HashSet<>();
for (int j = 0; j < debugNameCount; ++j) {
debugNames.add(input.readUTF());
}
node.getParameterDebugNames().add(debugNames);
}
}
private int packModifiers(Set<ElementModifier> modifiers) { private int packModifiers(Set<ElementModifier> modifiers) {
int packed = 0; int packed = 0;
for (ElementModifier modifier : modifiers) { for (ElementModifier modifier : modifiers) {
@ -257,10 +228,6 @@ public class AstIO {
try { try {
output.writeByte(statement.getLeftValue() != null ? 0 : 1); output.writeByte(statement.getLeftValue() != null ? 0 : 1);
writeLocation(statement.getLocation()); writeLocation(statement.getLocation());
output.writeShort(statement.getDebugNames().size());
for (String name : statement.getDebugNames()) {
output.writeUTF(name);
}
if (statement.getLeftValue() != null) { if (statement.getLeftValue() != null) {
writeExpr(statement.getLeftValue()); writeExpr(statement.getLeftValue());
} }
@ -674,10 +641,6 @@ public class AstIO {
case 0: { case 0: {
AssignmentStatement stmt = new AssignmentStatement(); AssignmentStatement stmt = new AssignmentStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(readLocation(input));
int debugNameCount = input.readShort();
for (int i = 0; i < debugNameCount; ++i) {
stmt.getDebugNames().add(input.readUTF());
}
stmt.setLeftValue(readExpr(input)); stmt.setLeftValue(readExpr(input));
stmt.setRightValue(readExpr(input)); stmt.setRightValue(readExpr(input));
stmt.setAsync(input.readBoolean()); stmt.setAsync(input.readBoolean());
@ -686,10 +649,6 @@ public class AstIO {
case 1: { case 1: {
AssignmentStatement stmt = new AssignmentStatement(); AssignmentStatement stmt = new AssignmentStatement();
stmt.setLocation(readLocation(input)); stmt.setLocation(readLocation(input));
int debugNameCount = input.readShort();
for (int i = 0; i < debugNameCount; ++i) {
stmt.getDebugNames().add(input.readUTF());
}
stmt.setRightValue(readExpr(input)); stmt.setRightValue(readExpr(input));
stmt.setAsync(input.readBoolean()); stmt.setAsync(input.readBoolean());
return stmt; return stmt;

View File

@ -43,10 +43,7 @@ public class ProgramIO {
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
Variable var = program.variableAt(i); Variable var = program.variableAt(i);
data.writeShort(var.getRegister()); data.writeShort(var.getRegister());
data.writeShort(var.getDebugNames().size()); data.writeUTF(var.getDebugName() != null ? var.getDebugName() : "");
for (String debugString : var.getDebugNames()) {
data.writeUTF(debugString);
}
} }
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock basicBlock = program.basicBlockAt(i); BasicBlock basicBlock = program.basicBlockAt(i);
@ -106,9 +103,9 @@ public class ProgramIO {
for (int i = 0; i < varCount; ++i) { for (int i = 0; i < varCount; ++i) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.setRegister(data.readShort()); var.setRegister(data.readShort());
int debugNameCount = data.readShort(); var.setDebugName(data.readUTF());
for (int j = 0; j < debugNameCount; ++j) { if (var.getDebugName().isEmpty()) {
var.getDebugNames().add(data.readUTF()); var.setDebugName(null);
} }
} }
for (int i = 0; i < basicBlockCount; ++i) { for (int i = 0; i < basicBlockCount; ++i) {

View File

@ -15,19 +15,14 @@
*/ */
package org.teavm.model; package org.teavm.model;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class Variable implements VariableReader { public class Variable implements VariableReader {
private Program program; private Program program;
private int index; private int index;
private int register; private int register;
private Set<String> debugNames; private String debugName;
Variable(Program program) { Variable(Program program) {
this.program = program; this.program = program;
this.debugNames = new HashSet<>();
} }
@Override @Override
@ -57,12 +52,12 @@ public class Variable implements VariableReader {
this.register = register; this.register = register;
} }
public Set<String> getDebugNames() { @Override
return debugNames; public String getDebugName() {
return debugName;
} }
@Override public void setDebugName(String debugName) {
public Set<String> readDebugNames() { this.debugName = debugName;
return Collections.unmodifiableSet(debugNames);
} }
} }

View File

@ -15,18 +15,12 @@
*/ */
package org.teavm.model; package org.teavm.model;
import java.util.Set;
/**
*
* @author Alexey Andreev
*/
public interface VariableReader { public interface VariableReader {
int getIndex(); int getIndex();
ProgramReader getProgram(); ProgramReader getProgram();
Set<String> readDebugNames(); String getDebugName();
int getRegister(); int getRegister();
} }

View File

@ -154,7 +154,7 @@ public class GlobalValueNumbering implements MethodOptimization {
if (map[i] != i) { if (map[i] != i) {
Variable var = program.variableAt(i); Variable var = program.variableAt(i);
Variable mapVar = program.variableAt(map[i]); Variable mapVar = program.variableAt(map[i]);
mapVar.getDebugNames().addAll(var.getDebugNames()); mapVar.setDebugName(var.getDebugName());
program.deleteVariable(i); program.deleteVariable(i);
} }
} }
@ -165,7 +165,12 @@ public class GlobalValueNumbering implements MethodOptimization {
} }
private void bind(int var, String value) { private void bind(int var, String value) {
KnownValue known = knownValues.get(value); String name = program.variableAt(var).getDebugName();
if (name == null) {
name = "";
}
KnownValue known = knownValues.get(name + ":" + value);
if (known != null && domTree.dominates(known.location, currentBlockIndex) && known.value != var) { if (known != null && domTree.dominates(known.location, currentBlockIndex) && known.value != var) {
eliminate = true; eliminate = true;
map[var] = known.value; map[var] = known.value;
@ -173,7 +178,7 @@ public class GlobalValueNumbering implements MethodOptimization {
known = new KnownValue(); known = new KnownValue();
known.location = currentBlockIndex; known.location = currentBlockIndex;
known.value = var; known.value = var;
knownValues.put(value, known); knownValues.put(name + ":" + value, known);
} }
} }

View File

@ -225,7 +225,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable();
var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); var.setDebugName(insn.getReceiver().getDebugName());
ClassConstantInstruction copy = new ClassConstantInstruction(); ClassConstantInstruction copy = new ClassConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -235,7 +235,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(NullConstantInstruction insn) { public void visit(NullConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable();
var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); var.setDebugName(insn.getReceiver().getDebugName());
NullConstantInstruction copy = new NullConstantInstruction(); NullConstantInstruction copy = new NullConstantInstruction();
copy.setReceiver(var); copy.setReceiver(var);
this.copy = copy; this.copy = copy;
@ -244,7 +244,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(IntegerConstantInstruction insn) { public void visit(IntegerConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable();
var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); var.setDebugName(insn.getReceiver().getDebugName());
IntegerConstantInstruction copy = new IntegerConstantInstruction(); IntegerConstantInstruction copy = new IntegerConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -254,7 +254,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(LongConstantInstruction insn) { public void visit(LongConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable();
var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); var.setDebugName(insn.getReceiver().getDebugName());
LongConstantInstruction copy = new LongConstantInstruction(); LongConstantInstruction copy = new LongConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -264,7 +264,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(FloatConstantInstruction insn) { public void visit(FloatConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable();
var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); var.setDebugName(insn.getReceiver().getDebugName());
FloatConstantInstruction copy = new FloatConstantInstruction(); FloatConstantInstruction copy = new FloatConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -274,7 +274,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(DoubleConstantInstruction insn) { public void visit(DoubleConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable();
var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); var.setDebugName(insn.getReceiver().getDebugName());
DoubleConstantInstruction copy = new DoubleConstantInstruction(); DoubleConstantInstruction copy = new DoubleConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);
@ -284,7 +284,7 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(StringConstantInstruction insn) { public void visit(StringConstantInstruction insn) {
var = program.createVariable(); var = program.createVariable();
var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); var.setDebugName(insn.getReceiver().getDebugName());
StringConstantInstruction copy = new StringConstantInstruction(); StringConstantInstruction copy = new StringConstantInstruction();
copy.setConstant(insn.getConstant()); copy.setConstant(insn.getConstant());
copy.setReceiver(var); copy.setReceiver(var);

View File

@ -193,7 +193,7 @@ public class AsyncProgramSplitter {
copy.createVariable(); copy.createVariable();
Variable varCopy = copy.variableAt(i); Variable varCopy = copy.variableAt(i);
varCopy.setRegister(var.getRegister()); varCopy.setRegister(var.getRegister());
varCopy.getDebugNames().addAll(var.getDebugNames()); varCopy.setDebugName(var.getDebugName());
} }
return copy; return copy;
} }

View File

@ -28,16 +28,8 @@ public class ListingBuilder {
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
sb.append(prefix).append("var @").append(i); sb.append(prefix).append("var @").append(i);
VariableReader var = program.variableAt(i); VariableReader var = program.variableAt(i);
if (var != null && !var.readDebugNames().isEmpty()) { if (var != null && var.getDebugName() != null) {
sb.append(" as "); sb.append(" as ").append(var.getDebugName());
boolean first = true;
for (String debugName : var.readDebugNames()) {
if (!first) {
sb.append(", ");
}
first = false;
sb.append(debugName);
}
} }
sb.append('\n'); sb.append('\n');
} }

View File

@ -200,7 +200,7 @@ public class PhiUpdater {
for (Phi phi : synthesizedPhis.get(index)) { for (Phi phi : synthesizedPhis.get(index)) {
Variable var = program.createVariable(); Variable var = program.createVariable();
var.getDebugNames().addAll(phi.getReceiver().getDebugNames()); var.setDebugName(phi.getReceiver().getDebugName());
variableMap[phi.getReceiver().getIndex()] = var; variableMap[phi.getReceiver().getIndex()] = var;
phi.setReceiver(var); phi.setReceiver(var);
} }
@ -287,7 +287,7 @@ public class PhiUpdater {
incoming.setSource(currentBlock); incoming.setSource(currentBlock);
incoming.setValue(var); incoming.setValue(var);
phi.getIncomings().add(incoming); phi.getIncomings().add(incoming);
phi.getReceiver().getDebugNames().addAll(var.getDebugNames()); phi.getReceiver().setDebugName(var.getDebugName());
} }
} }
} }

View File

@ -70,7 +70,7 @@ public final class ProgramUtils {
Program copy = new Program(); Program copy = new Program();
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
Variable var = copy.createVariable(); Variable var = copy.createVariable();
var.getDebugNames().addAll(program.variableAt(i).readDebugNames()); var.setDebugName(program.variableAt(i).getDebugName());
} }
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
copy.createBasicBlock(); copy.createBasicBlock();

View File

@ -257,14 +257,13 @@ public class RegisterAllocator {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
mapper.apply(block); mapper.apply(block);
} }
String[][] originalNames = new String[program.variableCount()][]; String[] originalNames = new String[program.variableCount()];
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
Variable var = program.variableAt(i); Variable var = program.variableAt(i);
originalNames[i] = var.getDebugNames().toArray(new String[0]); originalNames[i] = var.getDebugName();
var.getDebugNames().clear();
} }
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
program.variableAt(varMap[i]).getDebugNames().addAll(Arrays.asList(originalNames[i])); program.variableAt(varMap[i]).setDebugName(originalNames[i]);
} }
} }

View File

@ -20,6 +20,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -113,6 +114,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
private final Properties properties = new Properties(); private final Properties properties = new Properties();
private ProgramCache programCache; private ProgramCache programCache;
private boolean incremental; private boolean incremental;
private TeaVMOptimizationLevel optimizationLevel = TeaVMOptimizationLevel.SIMPLE;
private TeaVMProgressListener progressListener; private TeaVMProgressListener progressListener;
private boolean cancelled; private boolean cancelled;
private ListableClassHolderSource writtenClasses; private ListableClassHolderSource writtenClasses;
@ -202,6 +204,14 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
this.incremental = incremental; this.incremental = incremental;
} }
public TeaVMOptimizationLevel getOptimizationLevel() {
return optimizationLevel;
}
public void setOptimizationLevel(TeaVMOptimizationLevel optimizationLevel) {
this.optimizationLevel = optimizationLevel;
}
public TeaVMProgressListener getProgressListener() { public TeaVMProgressListener getProgressListener() {
return progressListener; return progressListener;
} }
@ -359,12 +369,13 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return; return;
} }
//inline(classSet); inline(classSet);
if (wasCancelled()) { if (wasCancelled()) {
return; return;
} }
} }
removeDebugNames(classSet);
optimize(classSet); optimize(classSet);
if (wasCancelled()) { if (wasCancelled()) {
return; return;
@ -423,10 +434,13 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
} }
private void inline(ListableClassHolderSource classes) { private void inline(ListableClassHolderSource classes) {
if (optimizationLevel != TeaVMOptimizationLevel.FULL) {
return;
}
Inlining inlining = new Inlining(); Inlining inlining = new Inlining();
for (String className : classes.getClassNames()) { for (String className : classes.getClassNames()) {
ClassHolder cls = classes.get(className); ClassHolder cls = classes.get(className);
for (final MethodHolder method : cls.getMethods()) { for (MethodHolder method : cls.getMethods()) {
if (method.getProgram() != null) { if (method.getProgram() != null) {
inlining.apply(method.getProgram(), classes); inlining.apply(method.getProgram(), classes);
} }
@ -437,6 +451,25 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
} }
} }
private void removeDebugNames(ListableClassHolderSource classes) {
if (optimizationLevel == TeaVMOptimizationLevel.SIMPLE) {
return;
}
for (String className : classes.getClassNames()) {
ClassHolder cls = classes.get(className);
for (MethodHolder method : cls.getMethods()) {
if (method.getProgram() != null) {
for (int i = 0; i < method.getProgram().variableCount(); ++i) {
method.getProgram().variableAt(i).setDebugName(null);
}
}
}
if (wasCancelled()) {
return;
}
}
}
private void optimize(ListableClassHolderSource classSource) { private void optimize(ListableClassHolderSource classSource) {
for (String className : classSource.getClassNames()) { for (String className : classSource.getClassNames()) {
ClassHolder cls = classSource.get(className); ClassHolder cls = classSource.get(className);
@ -481,17 +514,22 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
} }
private List<MethodOptimization> getOptimizations() { private List<MethodOptimization> getOptimizations() {
return Arrays.asList( List<MethodOptimization> optimizations = new ArrayList<>();
new RedundantJumpElimination(), optimizations.add(new RedundantJumpElimination());
new ArrayUnwrapMotion(), optimizations.add(new ArrayUnwrapMotion());
new LoopInversion(), if (optimizationLevel.ordinal() >= TeaVMOptimizationLevel.ADVANCED.ordinal()) {
new LoopInvariantMotion(), optimizations.add(new LoopInversion());
new GlobalValueNumbering(), optimizations.add(new LoopInvariantMotion());
new ConstantConditionElimination(), }
new RedundantJumpElimination(), optimizations.add(new GlobalValueNumbering());
new UnusedVariableElimination(), if (optimizationLevel.ordinal() >= TeaVMOptimizationLevel.ADVANCED.ordinal()) {
new ClassInitElimination(), optimizations.add(new ConstantConditionElimination());
new UnreachableBasicBlockElimination()); optimizations.add(new RedundantJumpElimination());
optimizations.add(new UnusedVariableElimination());
}
optimizations.add(new ClassInitElimination());
optimizations.add(new UnreachableBasicBlockElimination());
return optimizations;
} }
public void build(File dir, String fileName) { public void build(File dir, String fileName) {

View File

@ -0,0 +1,22 @@
/*
* Copyright 2016 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.vm;
public enum TeaVMOptimizationLevel {
SIMPLE,
ADVANCED,
FULL
}

View File

@ -170,8 +170,7 @@ class JSClassProcessor {
InstructionVariableMapper variableMapper = new InstructionVariableMapper(var -> InstructionVariableMapper variableMapper = new InstructionVariableMapper(var ->
program.variableAt(var.getIndex() + 1)); program.variableAt(var.getIndex() + 1));
for (int i = program.variableCount() - 1; i > 0; --i) { for (int i = program.variableCount() - 1; i > 0; --i) {
program.variableAt(i).getDebugNames().addAll(program.variableAt(i - 1).getDebugNames()); program.variableAt(i).setDebugName(program.variableAt(i - 1).getDebugName());
program.variableAt(i - 1).getDebugNames().clear();
} }
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);

View File

@ -24,6 +24,7 @@ import org.teavm.tooling.RuntimeCopyOperation;
import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTargetType;
import org.teavm.tooling.TeaVMTool; import org.teavm.tooling.TeaVMTool;
import org.teavm.tooling.TeaVMToolException; import org.teavm.tooling.TeaVMToolException;
import org.teavm.vm.TeaVMOptimizationLevel;
import org.teavm.vm.TeaVMPhase; import org.teavm.vm.TeaVMPhase;
import org.teavm.vm.TeaVMProgressFeedback; import org.teavm.vm.TeaVMProgressFeedback;
import org.teavm.vm.TeaVMProgressListener; import org.teavm.vm.TeaVMProgressListener;
@ -61,6 +62,9 @@ public final class TeaVMRunner {
.withDescription("causes TeaVM to generate minimized JavaScript file") .withDescription("causes TeaVM to generate minimized JavaScript file")
.withLongOpt("minify") .withLongOpt("minify")
.create("m")); .create("m"));
options.addOption(OptionBuilder
.withDescription("optimization level (1-3)")
.create("O"));
options.addOption(OptionBuilder options.addOption(OptionBuilder
.withArgName("separate|merge|none") .withArgName("separate|merge|none")
.hasArg() .hasArg()
@ -160,6 +164,33 @@ public final class TeaVMRunner {
if (commandLine.hasOption('D')) { if (commandLine.hasOption('D')) {
tool.setDebugInformationGenerated(true); tool.setDebugInformationGenerated(true);
} }
if (commandLine.hasOption("O")) {
int level;
try {
level = Integer.parseInt(commandLine.getOptionValue("O"));
} catch (NumberFormatException e) {
System.err.print("Wrong optimization level");
printUsage(options);
return;
}
switch (level) {
case 1:
tool.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
break;
case 2:
tool.setOptimizationLevel(TeaVMOptimizationLevel.ADVANCED);
break;
case 3:
tool.setOptimizationLevel(TeaVMOptimizationLevel.FULL);
break;
default:
System.err.print("Wrong optimization level");
printUsage(options);
return;
}
}
if (commandLine.hasOption('S')) { if (commandLine.hasOption('S')) {
tool.setSourceMapsFileGenerated(true); tool.setSourceMapsFileGenerated(true);
} }
@ -174,6 +205,7 @@ public final class TeaVMRunner {
if (commandLine.hasOption('p')) { if (commandLine.hasOption('p')) {
classPath = commandLine.getOptionValues('p'); classPath = commandLine.getOptionValues('p');
} }
boolean interactive = commandLine.hasOption('w'); boolean interactive = commandLine.hasOption('w');
args = commandLine.getArgs(); args = commandLine.getArgs();
if (args.length > 1) { if (args.length > 1) {

View File

@ -62,6 +62,7 @@ import org.teavm.vm.DirectoryBuildTarget;
import org.teavm.vm.TeaVM; import org.teavm.vm.TeaVM;
import org.teavm.vm.TeaVMBuilder; import org.teavm.vm.TeaVMBuilder;
import org.teavm.vm.TeaVMEntryPoint; import org.teavm.vm.TeaVMEntryPoint;
import org.teavm.vm.TeaVMOptimizationLevel;
import org.teavm.vm.TeaVMProgressListener; import org.teavm.vm.TeaVMProgressListener;
import org.teavm.vm.TeaVMTarget; import org.teavm.vm.TeaVMTarget;
import org.teavm.vm.spi.AbstractRendererListener; import org.teavm.vm.spi.AbstractRendererListener;
@ -93,6 +94,7 @@ public class TeaVMTool implements BaseTeaVMTool {
private boolean cancelled; private boolean cancelled;
private TeaVMProgressListener progressListener; private TeaVMProgressListener progressListener;
private TeaVM vm; private TeaVM vm;
private TeaVMOptimizationLevel optimizationLevel = TeaVMOptimizationLevel.SIMPLE;
private List<SourceFileProvider> sourceFileProviders = new ArrayList<>(); private List<SourceFileProvider> sourceFileProviders = new ArrayList<>();
private DebugInformationBuilder debugEmitter; private DebugInformationBuilder debugEmitter;
private JavaScriptTarget javaScriptTarget; private JavaScriptTarget javaScriptTarget;
@ -227,6 +229,14 @@ public class TeaVMTool implements BaseTeaVMTool {
this.targetType = targetType; this.targetType = targetType;
} }
public TeaVMOptimizationLevel getOptimizationLevel() {
return optimizationLevel;
}
public void setOptimizationLevel(TeaVMOptimizationLevel optimizationLevel) {
this.optimizationLevel = optimizationLevel;
}
public ClassLoader getClassLoader() { public ClassLoader getClassLoader() {
return classLoader; return classLoader;
} }
@ -361,6 +371,7 @@ public class TeaVMTool implements BaseTeaVMTool {
vm.setProperties(properties); vm.setProperties(properties);
vm.setProgramCache(programCache); vm.setProgramCache(programCache);
vm.setIncremental(incremental); vm.setIncremental(incremental);
vm.setOptimizationLevel(optimizationLevel);
vm.installPlugins(); vm.installPlugins();
for (ClassHolderTransformer transformer : transformers) { for (ClassHolderTransformer transformer : transformers) {