diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java index d7cd3c7b0..1b0781a25 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java @@ -49,7 +49,7 @@ public final class TArray extends TObject { @SuppressWarnings("unused") 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, diff --git a/core/src/main/java/org/teavm/ast/AssignmentStatement.java b/core/src/main/java/org/teavm/ast/AssignmentStatement.java index fc02e6f03..739941a48 100644 --- a/core/src/main/java/org/teavm/ast/AssignmentStatement.java +++ b/core/src/main/java/org/teavm/ast/AssignmentStatement.java @@ -15,15 +15,12 @@ */ package org.teavm.ast; -import java.util.HashSet; -import java.util.Set; import org.teavm.model.TextLocation; public class AssignmentStatement extends Statement { private Expr leftValue; private Expr rightValue; private TextLocation location; - private Set debugNames = new HashSet<>(); private boolean async; public Expr getLeftValue() { @@ -50,10 +47,6 @@ public class AssignmentStatement extends Statement { this.location = location; } - public Set getDebugNames() { - return debugNames; - } - public boolean isAsync() { return async; } diff --git a/core/src/main/java/org/teavm/ast/AsyncMethodNode.java b/core/src/main/java/org/teavm/ast/AsyncMethodNode.java index 187e7f75a..139fb11fa 100644 --- a/core/src/main/java/org/teavm/ast/AsyncMethodNode.java +++ b/core/src/main/java/org/teavm/ast/AsyncMethodNode.java @@ -17,8 +17,6 @@ package org.teavm.ast; import java.util.ArrayList; import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; import org.teavm.model.MethodReference; public class AsyncMethodNode extends MethodNode { @@ -33,19 +31,11 @@ public class AsyncMethodNode extends MethodNode { return body; } + @Override public List getVariables() { return variables; } - @Override - public List> getParameterDebugNames() { - return variables.subList(0, getReference().parameterCount()) - .stream() - .map(VariableNode::getDebugNames) - .collect(Collectors.toList()); - } - - @Override public void acceptVisitor(MethodNodeVisitor visitor) { visitor.visit(this); diff --git a/core/src/main/java/org/teavm/ast/MethodNode.java b/core/src/main/java/org/teavm/ast/MethodNode.java index 98ffa9bba..c32ff2dbd 100644 --- a/core/src/main/java/org/teavm/ast/MethodNode.java +++ b/core/src/main/java/org/teavm/ast/MethodNode.java @@ -42,5 +42,5 @@ public abstract class MethodNode { public abstract boolean isAsync(); - public abstract List> getParameterDebugNames(); + public abstract List getVariables(); } diff --git a/core/src/main/java/org/teavm/ast/NativeMethodNode.java b/core/src/main/java/org/teavm/ast/NativeMethodNode.java index ec925906a..6b931fad1 100644 --- a/core/src/main/java/org/teavm/ast/NativeMethodNode.java +++ b/core/src/main/java/org/teavm/ast/NativeMethodNode.java @@ -17,7 +17,6 @@ package org.teavm.ast; import java.util.Collections; import java.util.List; -import java.util.Set; import org.teavm.backend.javascript.spi.Generator; import org.teavm.model.MethodReference; @@ -52,7 +51,7 @@ public class NativeMethodNode extends MethodNode { } @Override - public List> getParameterDebugNames() { + public List getVariables() { return Collections.emptyList(); } } diff --git a/core/src/main/java/org/teavm/ast/RegularMethodNode.java b/core/src/main/java/org/teavm/ast/RegularMethodNode.java index a9b328e6a..95f4dc389 100644 --- a/core/src/main/java/org/teavm/ast/RegularMethodNode.java +++ b/core/src/main/java/org/teavm/ast/RegularMethodNode.java @@ -17,8 +17,6 @@ package org.teavm.ast; import java.util.ArrayList; import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; import org.teavm.model.MethodReference; public class RegularMethodNode extends MethodNode { @@ -37,18 +35,11 @@ public class RegularMethodNode extends MethodNode { this.body = body; } + @Override public List getVariables() { return variables; } - @Override - public List> getParameterDebugNames() { - return variables.subList(0, getReference().parameterCount()) - .stream() - .map(VariableNode::getDebugNames) - .collect(Collectors.toList()); - } - @Override public void acceptVisitor(MethodNodeVisitor visitor) { visitor.visit(this); diff --git a/core/src/main/java/org/teavm/ast/VariableNode.java b/core/src/main/java/org/teavm/ast/VariableNode.java index 0547a5583..2cc1fc28c 100644 --- a/core/src/main/java/org/teavm/ast/VariableNode.java +++ b/core/src/main/java/org/teavm/ast/VariableNode.java @@ -15,14 +15,12 @@ */ package org.teavm.ast; -import java.util.HashSet; -import java.util.Set; import org.teavm.model.util.VariableType; public class VariableNode { private int index; private VariableType type; - private Set debugNames = new HashSet<>(); + private String name; public VariableNode(int index, VariableType type) { this.index = index; @@ -45,7 +43,11 @@ public class VariableNode { this.type = type; } - public Set getDebugNames() { - return debugNames; + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; } } diff --git a/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java b/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java index 27c6b63f8..a6f0f361c 100644 --- a/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java +++ b/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java @@ -65,7 +65,6 @@ import org.teavm.model.Program; import org.teavm.model.TextLocation; import org.teavm.model.TryCatchBlock; import org.teavm.model.ValueType; -import org.teavm.model.Variable; import org.teavm.model.util.AsyncProgramSplitter; import org.teavm.model.util.ListingBuilder; import org.teavm.model.util.ProgramUtils; @@ -271,17 +270,14 @@ public class Decompiler { typeInferer.inferTypes(program, method.getReference()); for (int i = 0; i < program.variableCount(); ++i) { VariableNode variable = new VariableNode(program.variableAt(i).getRegister(), typeInferer.typeOf(i)); + variable.setName(program.variableAt(i).getDebugName()); methodNode.getVariables().add(variable); } Optimizer optimizer = new Optimizer(); optimizer.optimize(methodNode, method.getProgram()); 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; } @@ -338,17 +334,14 @@ public class Decompiler { typeInferer.inferTypes(program, method.getReference()); for (int i = 0; i < program.variableCount(); ++i) { VariableNode variable = new VariableNode(program.variableAt(i).getRegister(), typeInferer.typeOf(i)); + variable.setName(program.variableAt(i).getDebugName()); node.getVariables().add(variable); } Optimizer optimizer = new Optimizer(); optimizer.optimize(node, splitter); 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; } diff --git a/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java b/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java index 5a2899456..927bffc74 100644 --- a/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java +++ b/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java @@ -202,7 +202,6 @@ class StatementGenerator implements InstructionVisitor { public void visit(AssignInstruction insn) { AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), Expr.var(insn.getAssignee().getIndex())); - stmt.getDebugNames().addAll(insn.getReceiver().getDebugNames()); stmt.setLocation(currentLocation); statements.add(stmt); } @@ -500,7 +499,6 @@ class StatementGenerator implements InstructionVisitor { AssignmentStatement stmt; if (insn.getReceiver() != null) { stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), invocationExpr); - stmt.getDebugNames().addAll(insn.getReceiver().getDebugNames()); } else { stmt = Statement.assign(null, invocationExpr); } @@ -523,7 +521,6 @@ class StatementGenerator implements InstructionVisitor { private void assign(Expr source, Variable target) { AssignmentStatement stmt = Statement.assign(Expr.var(target.getIndex()), source); stmt.setLocation(currentLocation); - stmt.getDebugNames().addAll(target.getDebugNames()); statements.add(stmt); } diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index b249c23ae..32575eb51 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -126,8 +126,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext private boolean async; private Precedence precedence; private final Map blockIdMap = new HashMap<>(); - private final List> debugNames = new ArrayList<>(); private final List cachedVariableNames = new ArrayList<>(); + private MethodNode currentMethod; private boolean end; private int currentPart; private List postponedFieldInitializers = new ArrayList<>(); @@ -652,9 +652,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } private void renderBody(MethodNode method, boolean inner) throws IOException { - debugNames.clear(); + currentMethod = method; cachedVariableNames.clear(); - debugNames.addAll(method.getParameterDebugNames()); blockIdMap.clear(); MethodReference ref = method.getReference(); debugEmitter.emitMethod(ref.getDescriptor()); @@ -704,8 +703,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext Renderer.this.async = false; this.async = false; MethodReference ref = method.getReference(); - for (int i = 0; i < method.getParameterDebugNames().size(); ++i) { - debugEmitter.emitVariable(method.getParameterDebugNames().get(i).toArray(new String[0]), + for (int i = 0; i < method.getVariables().size(); ++i) { + debugEmitter.emitVariable(new String[] { method.getVariables().get(i).getName() }, variableName(i)); } @@ -748,8 +747,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext Renderer.this.async = true; this.async = true; MethodReference ref = methodNode.getReference(); - for (int i = 0; i < methodNode.getParameterDebugNames().size(); ++i) { - debugEmitter.emitVariable(methodNode.getParameterDebugNames().get(i).toArray(new String[0]), + for (int i = 0; i < methodNode.getVariables().size(); ++i) { + debugEmitter.emitVariable(new String[] { methodNode.getVariables().get(i).getName() }, variableName(i)); } int variableCount = 0; @@ -967,11 +966,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (statement.getLocation() != null) { 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) { throw new RenderingException("IO error occurred", e); } @@ -1258,7 +1252,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext return minifying ? "$t" : "$this"; } - Set names = index < debugNames.size() ? debugNames.get(index) : null; StringBuilder sb = new StringBuilder(); --index; if (index < variableNames.length()) { @@ -1267,11 +1260,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext sb.append(Character.toString(variableNames.charAt(index % variableNames.length())) + index / variableNames.length()); } - if (!minifying && names != null && !names.isEmpty()) { - List nameList = new ArrayList<>(names); - Collections.sort(nameList); - for (String name : nameList) { - sb.append('_').append(escapeName(name)); + if (!minifying) { + VariableNode variable = index < currentMethod.getVariables().size() + ? currentMethod.getVariables().get(index) + : null; + if (variable != null && variable.getName() != null) { + sb.setLength(0); + sb.append(escapeName(variable.getName())); } } return sb.toString(); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java index ba65dce97..ee2933749 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java @@ -65,7 +65,7 @@ public class WasmGenerator { WasmType type = variable.getType() != null ? WasmGeneratorUtil.mapType(variable.getType()) : WasmType.INT32; - function.add(new WasmLocal(type)); + function.add(new WasmLocal(type, variable.getName())); } for (int i = firstVariable; i <= methodReference.parameterCount(); ++i) { diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderer.java index 925fa745c..0011b59bc 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderer.java @@ -182,12 +182,16 @@ public class WasmCRenderer { } sb.append(WasmCRenderingVisitor.mapType(function.getResult())).append(' '); sb.append(function.getName()).append("("); + WasmCRenderingVisitor visitor = new WasmCRenderingVisitor(function.getResult(), function.getModule()); for (int i = 0; i < function.getParameters().size(); ++i) { if (i > 0) { sb.append(", "); } 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(")"); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java index 8d92b6227..471db52d4 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; 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.WasmType; import org.teavm.backend.wasm.model.expression.WasmBlock; @@ -303,7 +304,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { @Override public void visit(WasmGetLocal expression) { - value = new CExpression("var_" + expression.getLocal().getIndex()); + value = new CExpression(getVariableName(expression.getLocal())); } @Override @@ -313,7 +314,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { expression.getValue().acceptVisitor(this); result.getLines().addAll(value.getLines()); - result.addLine("var_" + expression.getLocal().getIndex() + " = " + value.getText() + ";", + result.addLine(getVariableName(expression.getLocal()) + " = " + value.getText() + ";", expression.getLocation()); value = result; @@ -1033,4 +1034,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { String temporaryVariable; WasmType type; } + + String getVariableName(WasmLocal local) { + if (local.getName() != null) { + return local.getName(); + } + return "var_" + local.getIndex(); + } } diff --git a/core/src/main/java/org/teavm/cache/AstIO.java b/core/src/main/java/org/teavm/cache/AstIO.java index 996a5306e..ec64750e2 100644 --- a/core/src/main/java/org/teavm/cache/AstIO.java +++ b/core/src/main/java/org/teavm/cache/AstIO.java @@ -20,7 +20,6 @@ import java.io.DataOutput; import java.io.IOException; import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -45,7 +44,6 @@ import org.teavm.ast.InitClassStatement; import org.teavm.ast.InstanceOfExpr; import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationType; -import org.teavm.ast.MethodNode; import org.teavm.ast.MonitorEnterStatement; import org.teavm.ast.MonitorExitStatement; import org.teavm.ast.NewArrayExpr; @@ -99,7 +97,6 @@ public class AstIO { for (VariableNode var : method.getVariables()) { write(output, var); } - output.writeShort(method.getParameterDebugNames().size()); try { method.getBody().acceptVisitor(new NodeWriter(output)); } catch (IOExceptionWrapper e) { @@ -110,10 +107,7 @@ public class AstIO { private void write(DataOutput output, VariableNode variable) throws IOException { output.writeShort(variable.getIndex()); output.writeByte(variable.getType().ordinal()); - output.writeByte(variable.getDebugNames().size()); - for (String debugName : variable.getDebugNames()) { - output.writeUTF(debugName); - } + output.writeUTF(variable.getName() != null ? variable.getName() : ""); } public RegularMethodNode read(DataInput input, MethodReference method) throws IOException { @@ -133,7 +127,10 @@ public class AstIO { VariableNode variable = new VariableNode(index, type); int nameCount = input.readByte(); 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; } @@ -144,8 +141,6 @@ public class AstIO { for (VariableNode var : method.getVariables()) { write(output, var); } - output.writeShort(method.getParameterDebugNames().size()); - writeParameters(output, method); try { output.writeShort(method.getBody().size()); 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 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 { AsyncMethodNode node = new AsyncMethodNode(method); node.getModifiers().addAll(unpackModifiers(input.readInt())); @@ -174,7 +158,6 @@ public class AstIO { for (int i = 0; i < varCount; ++i) { node.getVariables().add(readVariable(input)); } - readParameters(input, node); int partCount = input.readShort(); for (int i = 0; i < partCount; ++i) { AsyncMethodPart part = new AsyncMethodPart(); @@ -184,18 +167,6 @@ public class AstIO { 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 debugNames = new HashSet<>(); - for (int j = 0; j < debugNameCount; ++j) { - debugNames.add(input.readUTF()); - } - node.getParameterDebugNames().add(debugNames); - } - } - private int packModifiers(Set modifiers) { int packed = 0; for (ElementModifier modifier : modifiers) { @@ -257,10 +228,6 @@ public class AstIO { try { output.writeByte(statement.getLeftValue() != null ? 0 : 1); writeLocation(statement.getLocation()); - output.writeShort(statement.getDebugNames().size()); - for (String name : statement.getDebugNames()) { - output.writeUTF(name); - } if (statement.getLeftValue() != null) { writeExpr(statement.getLeftValue()); } @@ -674,10 +641,6 @@ public class AstIO { case 0: { AssignmentStatement stmt = new AssignmentStatement(); 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.setRightValue(readExpr(input)); stmt.setAsync(input.readBoolean()); @@ -686,10 +649,6 @@ public class AstIO { case 1: { AssignmentStatement stmt = new AssignmentStatement(); 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.setAsync(input.readBoolean()); return stmt; diff --git a/core/src/main/java/org/teavm/cache/ProgramIO.java b/core/src/main/java/org/teavm/cache/ProgramIO.java index fd8278f61..944b4eaa2 100644 --- a/core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/core/src/main/java/org/teavm/cache/ProgramIO.java @@ -43,10 +43,7 @@ public class ProgramIO { for (int i = 0; i < program.variableCount(); ++i) { Variable var = program.variableAt(i); data.writeShort(var.getRegister()); - data.writeShort(var.getDebugNames().size()); - for (String debugString : var.getDebugNames()) { - data.writeUTF(debugString); - } + data.writeUTF(var.getDebugName() != null ? var.getDebugName() : ""); } for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock basicBlock = program.basicBlockAt(i); @@ -106,9 +103,9 @@ public class ProgramIO { for (int i = 0; i < varCount; ++i) { Variable var = program.createVariable(); var.setRegister(data.readShort()); - int debugNameCount = data.readShort(); - for (int j = 0; j < debugNameCount; ++j) { - var.getDebugNames().add(data.readUTF()); + var.setDebugName(data.readUTF()); + if (var.getDebugName().isEmpty()) { + var.setDebugName(null); } } for (int i = 0; i < basicBlockCount; ++i) { diff --git a/core/src/main/java/org/teavm/model/Variable.java b/core/src/main/java/org/teavm/model/Variable.java index cb13eda2b..5d469c6a1 100644 --- a/core/src/main/java/org/teavm/model/Variable.java +++ b/core/src/main/java/org/teavm/model/Variable.java @@ -15,19 +15,14 @@ */ package org.teavm.model; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - public class Variable implements VariableReader { private Program program; private int index; private int register; - private Set debugNames; + private String debugName; Variable(Program program) { this.program = program; - this.debugNames = new HashSet<>(); } @Override @@ -57,12 +52,12 @@ public class Variable implements VariableReader { this.register = register; } - public Set getDebugNames() { - return debugNames; + @Override + public String getDebugName() { + return debugName; } - @Override - public Set readDebugNames() { - return Collections.unmodifiableSet(debugNames); + public void setDebugName(String debugName) { + this.debugName = debugName; } } diff --git a/core/src/main/java/org/teavm/model/VariableReader.java b/core/src/main/java/org/teavm/model/VariableReader.java index 58637c520..4271035a3 100644 --- a/core/src/main/java/org/teavm/model/VariableReader.java +++ b/core/src/main/java/org/teavm/model/VariableReader.java @@ -15,18 +15,12 @@ */ package org.teavm.model; -import java.util.Set; - -/** - * - * @author Alexey Andreev - */ public interface VariableReader { int getIndex(); ProgramReader getProgram(); - Set readDebugNames(); + String getDebugName(); int getRegister(); } diff --git a/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java b/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java index 1e7363718..aaf78758b 100644 --- a/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java +++ b/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java @@ -154,7 +154,7 @@ public class GlobalValueNumbering implements MethodOptimization { if (map[i] != i) { Variable var = program.variableAt(i); Variable mapVar = program.variableAt(map[i]); - mapVar.getDebugNames().addAll(var.getDebugNames()); + mapVar.setDebugName(var.getDebugName()); program.deleteVariable(i); } } @@ -165,7 +165,12 @@ public class GlobalValueNumbering implements MethodOptimization { } 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) { eliminate = true; map[var] = known.value; @@ -173,7 +178,7 @@ public class GlobalValueNumbering implements MethodOptimization { known = new KnownValue(); known.location = currentBlockIndex; known.value = var; - knownValues.put(value, known); + knownValues.put(name + ":" + value, known); } } diff --git a/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java b/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java index 4aa22b8ad..585bba2bf 100644 --- a/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java +++ b/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java @@ -225,7 +225,7 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(ClassConstantInstruction insn) { var = program.createVariable(); - var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); + var.setDebugName(insn.getReceiver().getDebugName()); ClassConstantInstruction copy = new ClassConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -235,7 +235,7 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(NullConstantInstruction insn) { var = program.createVariable(); - var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); + var.setDebugName(insn.getReceiver().getDebugName()); NullConstantInstruction copy = new NullConstantInstruction(); copy.setReceiver(var); this.copy = copy; @@ -244,7 +244,7 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(IntegerConstantInstruction insn) { var = program.createVariable(); - var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); + var.setDebugName(insn.getReceiver().getDebugName()); IntegerConstantInstruction copy = new IntegerConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -254,7 +254,7 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(LongConstantInstruction insn) { var = program.createVariable(); - var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); + var.setDebugName(insn.getReceiver().getDebugName()); LongConstantInstruction copy = new LongConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -264,7 +264,7 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(FloatConstantInstruction insn) { var = program.createVariable(); - var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); + var.setDebugName(insn.getReceiver().getDebugName()); FloatConstantInstruction copy = new FloatConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -274,7 +274,7 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(DoubleConstantInstruction insn) { var = program.createVariable(); - var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); + var.setDebugName(insn.getReceiver().getDebugName()); DoubleConstantInstruction copy = new DoubleConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); @@ -284,7 +284,7 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(StringConstantInstruction insn) { var = program.createVariable(); - var.getDebugNames().addAll(insn.getReceiver().getDebugNames()); + var.setDebugName(insn.getReceiver().getDebugName()); StringConstantInstruction copy = new StringConstantInstruction(); copy.setConstant(insn.getConstant()); copy.setReceiver(var); diff --git a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java index 009b961fe..8ddc6a064 100644 --- a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java +++ b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java @@ -193,7 +193,7 @@ public class AsyncProgramSplitter { copy.createVariable(); Variable varCopy = copy.variableAt(i); varCopy.setRegister(var.getRegister()); - varCopy.getDebugNames().addAll(var.getDebugNames()); + varCopy.setDebugName(var.getDebugName()); } return copy; } diff --git a/core/src/main/java/org/teavm/model/util/ListingBuilder.java b/core/src/main/java/org/teavm/model/util/ListingBuilder.java index 5247c67ae..f4dc79071 100644 --- a/core/src/main/java/org/teavm/model/util/ListingBuilder.java +++ b/core/src/main/java/org/teavm/model/util/ListingBuilder.java @@ -28,16 +28,8 @@ public class ListingBuilder { for (int i = 0; i < program.variableCount(); ++i) { sb.append(prefix).append("var @").append(i); VariableReader var = program.variableAt(i); - if (var != null && !var.readDebugNames().isEmpty()) { - sb.append(" as "); - boolean first = true; - for (String debugName : var.readDebugNames()) { - if (!first) { - sb.append(", "); - } - first = false; - sb.append(debugName); - } + if (var != null && var.getDebugName() != null) { + sb.append(" as ").append(var.getDebugName()); } sb.append('\n'); } diff --git a/core/src/main/java/org/teavm/model/util/PhiUpdater.java b/core/src/main/java/org/teavm/model/util/PhiUpdater.java index 4101c9b0a..10b0c9071 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -200,7 +200,7 @@ public class PhiUpdater { for (Phi phi : synthesizedPhis.get(index)) { Variable var = program.createVariable(); - var.getDebugNames().addAll(phi.getReceiver().getDebugNames()); + var.setDebugName(phi.getReceiver().getDebugName()); variableMap[phi.getReceiver().getIndex()] = var; phi.setReceiver(var); } @@ -287,7 +287,7 @@ public class PhiUpdater { incoming.setSource(currentBlock); incoming.setValue(var); phi.getIncomings().add(incoming); - phi.getReceiver().getDebugNames().addAll(var.getDebugNames()); + phi.getReceiver().setDebugName(var.getDebugName()); } } } diff --git a/core/src/main/java/org/teavm/model/util/ProgramUtils.java b/core/src/main/java/org/teavm/model/util/ProgramUtils.java index e000227c4..f9bf394b4 100644 --- a/core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -70,7 +70,7 @@ public final class ProgramUtils { Program copy = new Program(); for (int i = 0; i < program.variableCount(); ++i) { 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) { copy.createBasicBlock(); diff --git a/core/src/main/java/org/teavm/model/util/RegisterAllocator.java b/core/src/main/java/org/teavm/model/util/RegisterAllocator.java index b5f9be8d1..b5d34e7aa 100644 --- a/core/src/main/java/org/teavm/model/util/RegisterAllocator.java +++ b/core/src/main/java/org/teavm/model/util/RegisterAllocator.java @@ -257,14 +257,13 @@ public class RegisterAllocator { BasicBlock block = program.basicBlockAt(i); mapper.apply(block); } - String[][] originalNames = new String[program.variableCount()][]; + String[] originalNames = new String[program.variableCount()]; for (int i = 0; i < program.variableCount(); ++i) { Variable var = program.variableAt(i); - originalNames[i] = var.getDebugNames().toArray(new String[0]); - var.getDebugNames().clear(); + originalNames[i] = var.getDebugName(); } 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]); } } diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index 7d2cd4b4c..598328b8c 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -20,6 +20,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -113,6 +114,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { private final Properties properties = new Properties(); private ProgramCache programCache; private boolean incremental; + private TeaVMOptimizationLevel optimizationLevel = TeaVMOptimizationLevel.SIMPLE; private TeaVMProgressListener progressListener; private boolean cancelled; private ListableClassHolderSource writtenClasses; @@ -202,6 +204,14 @@ public class TeaVM implements TeaVMHost, ServiceRepository { this.incremental = incremental; } + public TeaVMOptimizationLevel getOptimizationLevel() { + return optimizationLevel; + } + + public void setOptimizationLevel(TeaVMOptimizationLevel optimizationLevel) { + this.optimizationLevel = optimizationLevel; + } + public TeaVMProgressListener getProgressListener() { return progressListener; } @@ -359,12 +369,13 @@ public class TeaVM implements TeaVMHost, ServiceRepository { return; } - //inline(classSet); + inline(classSet); if (wasCancelled()) { return; } } + removeDebugNames(classSet); optimize(classSet); if (wasCancelled()) { return; @@ -423,10 +434,13 @@ public class TeaVM implements TeaVMHost, ServiceRepository { } private void inline(ListableClassHolderSource classes) { + if (optimizationLevel != TeaVMOptimizationLevel.FULL) { + return; + } Inlining inlining = new Inlining(); for (String className : classes.getClassNames()) { ClassHolder cls = classes.get(className); - for (final MethodHolder method : cls.getMethods()) { + for (MethodHolder method : cls.getMethods()) { if (method.getProgram() != null) { 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) { for (String className : classSource.getClassNames()) { ClassHolder cls = classSource.get(className); @@ -481,17 +514,22 @@ public class TeaVM implements TeaVMHost, ServiceRepository { } private List getOptimizations() { - return Arrays.asList( - new RedundantJumpElimination(), - new ArrayUnwrapMotion(), - new LoopInversion(), - new LoopInvariantMotion(), - new GlobalValueNumbering(), - new ConstantConditionElimination(), - new RedundantJumpElimination(), - new UnusedVariableElimination(), - new ClassInitElimination(), - new UnreachableBasicBlockElimination()); + List optimizations = new ArrayList<>(); + optimizations.add(new RedundantJumpElimination()); + optimizations.add(new ArrayUnwrapMotion()); + if (optimizationLevel.ordinal() >= TeaVMOptimizationLevel.ADVANCED.ordinal()) { + optimizations.add(new LoopInversion()); + optimizations.add(new LoopInvariantMotion()); + } + optimizations.add(new GlobalValueNumbering()); + if (optimizationLevel.ordinal() >= TeaVMOptimizationLevel.ADVANCED.ordinal()) { + optimizations.add(new ConstantConditionElimination()); + 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) { diff --git a/core/src/main/java/org/teavm/vm/TeaVMOptimizationLevel.java b/core/src/main/java/org/teavm/vm/TeaVMOptimizationLevel.java new file mode 100644 index 000000000..8fab8d9cf --- /dev/null +++ b/core/src/main/java/org/teavm/vm/TeaVMOptimizationLevel.java @@ -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 +} diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java index 76629e62a..0c7a06a99 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java @@ -170,8 +170,7 @@ class JSClassProcessor { InstructionVariableMapper variableMapper = new InstructionVariableMapper(var -> program.variableAt(var.getIndex() + 1)); for (int i = program.variableCount() - 1; i > 0; --i) { - program.variableAt(i).getDebugNames().addAll(program.variableAt(i - 1).getDebugNames()); - program.variableAt(i - 1).getDebugNames().clear(); + program.variableAt(i).setDebugName(program.variableAt(i - 1).getDebugName()); } for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); diff --git a/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java b/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java index 761dc2efd..9f6cd1176 100644 --- a/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java +++ b/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java @@ -24,6 +24,7 @@ import org.teavm.tooling.RuntimeCopyOperation; import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTool; import org.teavm.tooling.TeaVMToolException; +import org.teavm.vm.TeaVMOptimizationLevel; import org.teavm.vm.TeaVMPhase; import org.teavm.vm.TeaVMProgressFeedback; import org.teavm.vm.TeaVMProgressListener; @@ -61,6 +62,9 @@ public final class TeaVMRunner { .withDescription("causes TeaVM to generate minimized JavaScript file") .withLongOpt("minify") .create("m")); + options.addOption(OptionBuilder + .withDescription("optimization level (1-3)") + .create("O")); options.addOption(OptionBuilder .withArgName("separate|merge|none") .hasArg() @@ -160,6 +164,33 @@ public final class TeaVMRunner { if (commandLine.hasOption('D')) { 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')) { tool.setSourceMapsFileGenerated(true); } @@ -174,6 +205,7 @@ public final class TeaVMRunner { if (commandLine.hasOption('p')) { classPath = commandLine.getOptionValues('p'); } + boolean interactive = commandLine.hasOption('w'); args = commandLine.getArgs(); if (args.length > 1) { diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java index 0ddd401bf..e7a3c7241 100644 --- a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -62,6 +62,7 @@ import org.teavm.vm.DirectoryBuildTarget; import org.teavm.vm.TeaVM; import org.teavm.vm.TeaVMBuilder; import org.teavm.vm.TeaVMEntryPoint; +import org.teavm.vm.TeaVMOptimizationLevel; import org.teavm.vm.TeaVMProgressListener; import org.teavm.vm.TeaVMTarget; import org.teavm.vm.spi.AbstractRendererListener; @@ -93,6 +94,7 @@ public class TeaVMTool implements BaseTeaVMTool { private boolean cancelled; private TeaVMProgressListener progressListener; private TeaVM vm; + private TeaVMOptimizationLevel optimizationLevel = TeaVMOptimizationLevel.SIMPLE; private List sourceFileProviders = new ArrayList<>(); private DebugInformationBuilder debugEmitter; private JavaScriptTarget javaScriptTarget; @@ -227,6 +229,14 @@ public class TeaVMTool implements BaseTeaVMTool { this.targetType = targetType; } + public TeaVMOptimizationLevel getOptimizationLevel() { + return optimizationLevel; + } + + public void setOptimizationLevel(TeaVMOptimizationLevel optimizationLevel) { + this.optimizationLevel = optimizationLevel; + } + public ClassLoader getClassLoader() { return classLoader; } @@ -361,6 +371,7 @@ public class TeaVMTool implements BaseTeaVMTool { vm.setProperties(properties); vm.setProgramCache(programCache); vm.setIncremental(incremental); + vm.setOptimizationLevel(optimizationLevel); vm.installPlugins(); for (ClassHolderTransformer transformer : transformers) {