diff --git a/core/src/main/java/org/teavm/ast/AsyncMethodNode.java b/core/src/main/java/org/teavm/ast/AsyncMethodNode.java index fbf44613f..187e7f75a 100644 --- a/core/src/main/java/org/teavm/ast/AsyncMethodNode.java +++ b/core/src/main/java/org/teavm/ast/AsyncMethodNode.java @@ -18,16 +18,12 @@ 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; -/** - * - * @author Alexey Andreev - */ public class AsyncMethodNode extends MethodNode { private List body = new ArrayList<>(); - private List variables = new ArrayList<>(); - private List> parameterDebugNames = new ArrayList<>(); + private List variables = new ArrayList<>(); public AsyncMethodNode(MethodReference reference) { super(reference); @@ -37,15 +33,19 @@ public class AsyncMethodNode extends MethodNode { return body; } - public List getVariables() { + public List getVariables() { return variables; } @Override public List> getParameterDebugNames() { - return parameterDebugNames; + 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/NativeMethodNode.java b/core/src/main/java/org/teavm/ast/NativeMethodNode.java index c672da3e7..93082f062 100644 --- a/core/src/main/java/org/teavm/ast/NativeMethodNode.java +++ b/core/src/main/java/org/teavm/ast/NativeMethodNode.java @@ -21,10 +21,6 @@ import java.util.Set; import org.teavm.javascript.spi.Generator; import org.teavm.model.MethodReference; -/** - * - * @author Alexey Andreev - */ public class NativeMethodNode extends MethodNode { private Generator generator; private boolean async; diff --git a/core/src/main/java/org/teavm/ast/RegularMethodNode.java b/core/src/main/java/org/teavm/ast/RegularMethodNode.java index 19b827c25..a9b328e6a 100644 --- a/core/src/main/java/org/teavm/ast/RegularMethodNode.java +++ b/core/src/main/java/org/teavm/ast/RegularMethodNode.java @@ -18,12 +18,12 @@ 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 { private Statement body; - private List variables = new ArrayList<>(); - private List> parameterDebugNames = new ArrayList<>(); + private List variables = new ArrayList<>(); public RegularMethodNode(MethodReference reference) { super(reference); @@ -37,13 +37,16 @@ public class RegularMethodNode extends MethodNode { this.body = body; } - public List getVariables() { + public List getVariables() { return variables; } @Override public List> getParameterDebugNames() { - return parameterDebugNames; + return variables.subList(0, getReference().parameterCount()) + .stream() + .map(VariableNode::getDebugNames) + .collect(Collectors.toList()); } @Override diff --git a/core/src/main/java/org/teavm/ast/VariableNode.java b/core/src/main/java/org/teavm/ast/VariableNode.java new file mode 100644 index 000000000..0547a5583 --- /dev/null +++ b/core/src/main/java/org/teavm/ast/VariableNode.java @@ -0,0 +1,51 @@ +/* + * 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.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<>(); + + public VariableNode(int index, VariableType type) { + this.index = index; + this.type = type; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public VariableType getType() { + return type; + } + + public void setType(VariableType type) { + this.type = type; + } + + public Set getDebugNames() { + return debugNames; + } +} 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 fe65cbd55..fee4d67ca 100644 --- a/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java +++ b/core/src/main/java/org/teavm/ast/decompilation/Decompiler.java @@ -43,6 +43,7 @@ import org.teavm.ast.RegularMethodNode; import org.teavm.ast.SequentialStatement; import org.teavm.ast.Statement; import org.teavm.ast.TryCatchStatement; +import org.teavm.ast.VariableNode; import org.teavm.ast.WhileStatement; import org.teavm.ast.cache.MethodNodeCache; import org.teavm.ast.optimization.Optimizer; @@ -71,6 +72,7 @@ import org.teavm.model.Variable; import org.teavm.model.util.AsyncProgramSplitter; import org.teavm.model.util.ListingBuilder; import org.teavm.model.util.ProgramUtils; +import org.teavm.model.util.TypeInferer; public class Decompiler { private ClassHolderSource classSource; @@ -267,9 +269,14 @@ public class Decompiler { sb.append(new ListingBuilder().buildListing(program, " ")); throw new DecompilationException(sb.toString(), e); } + + TypeInferer typeInferer = new TypeInferer(); + typeInferer.inferTypes(program, method.getReference()); for (int i = 0; i < program.variableCount(); ++i) { - methodNode.getVariables().add(program.variableAt(i).getRegister()); + VariableNode variable = new VariableNode(program.variableAt(i).getRegister(), typeInferer.typeOf(i)); + methodNode.getVariables().add(variable); } + Optimizer optimizer = new Optimizer(); optimizer.optimize(methodNode, method.getProgram()); methodNode.getModifiers().addAll(mapModifiers(method.getModifiers())); @@ -328,10 +335,15 @@ public class Decompiler { } node.getBody().add(part); } + Program program = method.getProgram(); + TypeInferer typeInferer = new TypeInferer(); + typeInferer.inferTypes(program, method.getReference()); for (int i = 0; i < program.variableCount(); ++i) { - node.getVariables().add(program.variableAt(i).getRegister()); + VariableNode variable = new VariableNode(program.variableAt(i).getRegister(), typeInferer.typeOf(i)); + node.getVariables().add(variable); } + Optimizer optimizer = new Optimizer(); optimizer.optimize(node, splitter); node.getModifiers().addAll(mapModifiers(method.getModifiers())); diff --git a/core/src/main/java/org/teavm/ast/optimization/Optimizer.java b/core/src/main/java/org/teavm/ast/optimization/Optimizer.java index b256c4892..7259d7035 100644 --- a/core/src/main/java/org/teavm/ast/optimization/Optimizer.java +++ b/core/src/main/java/org/teavm/ast/optimization/Optimizer.java @@ -46,13 +46,17 @@ public class Optimizer { method.getBody().acceptVisitor(optimizer); method.setBody(optimizer.resultStmt); int paramCount = method.getReference().parameterCount(); + UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables()); method.getBody().acceptVisitor(unusedEliminator); - method.getVariables().subList(unusedEliminator.lastIndex, method.getVariables().size()).clear(); + method.getVariables().clear(); + method.getVariables().addAll(unusedEliminator.getReorderedVariables()); + RedundantLabelEliminator labelEliminator = new RedundantLabelEliminator(); method.getBody().acceptVisitor(labelEliminator); + for (int i = 0; i < method.getVariables().size(); ++i) { - method.getVariables().set(i, i); + method.getVariables().get(i).setIndex(i); } } @@ -80,18 +84,21 @@ public class Optimizer { part.getStatement().acceptVisitor(optimizer); part.setStatement(optimizer.resultStmt); } + int paramCount = method.getReference().parameterCount(); UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables()); for (AsyncMethodPart part : method.getBody()) { part.getStatement().acceptVisitor(unusedEliminator); } - method.getVariables().subList(unusedEliminator.lastIndex, method.getVariables().size()).clear(); + method.getVariables().clear(); + method.getVariables().addAll(unusedEliminator.getReorderedVariables()); + RedundantLabelEliminator labelEliminator = new RedundantLabelEliminator(); for (AsyncMethodPart part : method.getBody()) { part.getStatement().acceptVisitor(labelEliminator); } for (int i = 0; i < method.getVariables().size(); ++i) { - method.getVariables().set(i, i); + method.getVariables().get(i).setIndex(i); } } diff --git a/core/src/main/java/org/teavm/ast/optimization/UnusedVariableEliminator.java b/core/src/main/java/org/teavm/ast/optimization/UnusedVariableEliminator.java index 8a79d7481..0c9d4face 100644 --- a/core/src/main/java/org/teavm/ast/optimization/UnusedVariableEliminator.java +++ b/core/src/main/java/org/teavm/ast/optimization/UnusedVariableEliminator.java @@ -15,6 +15,7 @@ */ package org.teavm.ast.optimization; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.teavm.ast.AssignmentStatement; @@ -51,18 +52,23 @@ import org.teavm.ast.TryCatchStatement; import org.teavm.ast.UnaryExpr; import org.teavm.ast.UnwrapArrayExpr; import org.teavm.ast.VariableExpr; +import org.teavm.ast.VariableNode; import org.teavm.ast.WhileStatement; class UnusedVariableEliminator implements ExprVisitor, StatementVisitor { + private final VariableNode[] variableNodes; private final int[] variables; private final int[] indexes; + private List reorderedVariables = new ArrayList<>(); int lastIndex; - UnusedVariableEliminator(int parameterCount, List variables) { + UnusedVariableEliminator(int parameterCount, List variables) { + variableNodes = new VariableNode[variables.size()]; this.variables = new int[variables.size()]; int variableCount = 0; for (int i = 0; i < variables.size(); ++i) { - int var = variables.get(i); + variableNodes[i] = variables.get(i); + int var = variables.get(i).getIndex(); this.variables[i] = var; variableCount = Math.max(variableCount, var + 1); } @@ -71,9 +77,14 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor { parameterCount = Math.min(parameterCount, indexes.length - 1); for (int i = 0; i <= parameterCount; ++i) { indexes[i] = lastIndex++; + reorderedVariables.add(variableNodes[i]); } } + public List getReorderedVariables() { + return reorderedVariables; + } + @Override public void visit(AssignmentStatement statement) { if (statement.getLeftValue() != null) { @@ -155,6 +166,7 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor { if (index == -1) { index = lastIndex++; indexes[variables[var]] = index; + reorderedVariables.add(variableNodes[var]); } return index; } diff --git a/core/src/main/java/org/teavm/cache/AstIO.java b/core/src/main/java/org/teavm/cache/AstIO.java index fb6a7dfc2..d358b2c6a 100644 --- a/core/src/main/java/org/teavm/cache/AstIO.java +++ b/core/src/main/java/org/teavm/cache/AstIO.java @@ -70,12 +70,14 @@ import org.teavm.ast.UnaryExpr; import org.teavm.ast.UnaryOperation; import org.teavm.ast.UnwrapArrayExpr; import org.teavm.ast.VariableExpr; +import org.teavm.ast.VariableNode; import org.teavm.ast.WhileStatement; import org.teavm.model.FieldReference; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; import org.teavm.model.instructions.ArrayElementType; +import org.teavm.model.util.VariableType; public class AstIO { private static final NodeModifier[] nodeModifiers = NodeModifier.values(); @@ -94,11 +96,10 @@ public class AstIO { public void write(DataOutput output, RegularMethodNode method) throws IOException { output.writeInt(packModifiers(method.getModifiers())); output.writeShort(method.getVariables().size()); - for (int var : method.getVariables()) { - output.writeShort(var); + for (VariableNode var : method.getVariables()) { + write(output, var); } output.writeShort(method.getParameterDebugNames().size()); - writeParameters(output, method); try { method.getBody().acceptVisitor(new NodeWriter(output)); } catch (IOExceptionWrapper e) { @@ -106,23 +107,42 @@ 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); + } + } + public RegularMethodNode read(DataInput input, MethodReference method) throws IOException { RegularMethodNode node = new RegularMethodNode(method); node.getModifiers().addAll(unpackModifiers(input.readInt())); int varCount = input.readShort(); for (int i = 0; i < varCount; ++i) { - node.getVariables().add((int) input.readShort()); + node.getVariables().add(readVariable(input)); } - readParameters(input, node); node.setBody(readStatement(input)); return node; } + private VariableNode readVariable(DataInput input) throws IOException { + int index = input.readShort(); + VariableType type = VariableType.values()[input.readByte()]; + VariableNode variable = new VariableNode(index, type); + int nameCount = input.readByte(); + for (int i = 0; i < nameCount; ++i) { + variable.getDebugNames().add(input.readUTF()); + } + return variable; + } + public void writeAsync(DataOutput output, AsyncMethodNode method) throws IOException { output.writeInt(packModifiers(method.getModifiers())); output.writeShort(method.getVariables().size()); - for (int var : method.getVariables()) { - output.writeShort(var); + for (VariableNode var : method.getVariables()) { + write(output, var); } output.writeShort(method.getParameterDebugNames().size()); writeParameters(output, method); @@ -152,7 +172,7 @@ public class AstIO { node.getModifiers().addAll(unpackModifiers(input.readInt())); int varCount = input.readShort(); for (int i = 0; i < varCount; ++i) { - node.getVariables().add((int) input.readShort()); + node.getVariables().add(readVariable(input)); } readParameters(input, node); int partCount = input.readShort(); diff --git a/core/src/main/java/org/teavm/javascript/Renderer.java b/core/src/main/java/org/teavm/javascript/Renderer.java index e97ab92a8..51886a614 100644 --- a/core/src/main/java/org/teavm/javascript/Renderer.java +++ b/core/src/main/java/org/teavm/javascript/Renderer.java @@ -75,6 +75,7 @@ import org.teavm.ast.TryCatchStatement; import org.teavm.ast.UnaryExpr; import org.teavm.ast.UnwrapArrayExpr; import org.teavm.ast.VariableExpr; +import org.teavm.ast.VariableNode; import org.teavm.ast.WhileStatement; import org.teavm.codegen.NamingException; import org.teavm.codegen.NamingOrderer; @@ -709,8 +710,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } int variableCount = 0; - for (int var : method.getVariables()) { - variableCount = Math.max(variableCount, var + 1); + for (VariableNode var : method.getVariables()) { + variableCount = Math.max(variableCount, var.getIndex() + 1); } TryCatchFinder tryCatchFinder = new TryCatchFinder(); method.getBody().acceptVisitor(tryCatchFinder); @@ -752,8 +753,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext variableName(i)); } int variableCount = 0; - for (int var : methodNode.getVariables()) { - variableCount = Math.max(variableCount, var + 1); + for (VariableNode var : methodNode.getVariables()) { + variableCount = Math.max(variableCount, var.getIndex() + 1); } List variableNames = new ArrayList<>(); for (int i = ref.parameterCount() + 1; i < variableCount; ++i) { diff --git a/core/src/main/java/org/teavm/wasm/WasmTarget.java b/core/src/main/java/org/teavm/wasm/WasmTarget.java index f3c31c726..c9beb04eb 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -35,6 +35,7 @@ import org.teavm.model.CallLocation; import org.teavm.model.ClassHolder; import org.teavm.model.ClassReader; import org.teavm.model.ElementModifier; +import org.teavm.model.FieldReference; import org.teavm.model.Instruction; import org.teavm.model.ListableClassHolderSource; import org.teavm.model.ListableClassReaderSource; @@ -122,6 +123,8 @@ public class WasmTarget implements TeaVMTarget { RuntimeClass.class, int.class, Address.class), null).use(); dependencyChecker.linkMethod(new MethodReference(Allocator.class, "", void.class), null).use(); + + dependencyChecker.linkField(new FieldReference("java.lang.Object", "monitor"), null); } @Override diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java index 29206d824..e46f29f85 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java @@ -16,18 +16,14 @@ package org.teavm.wasm.generate; import org.teavm.ast.RegularMethodNode; +import org.teavm.ast.VariableNode; import org.teavm.ast.decompilation.Decompiler; -import org.teavm.common.IntegerArray; import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolderSource; import org.teavm.model.ElementModifier; import org.teavm.model.MethodHolder; import org.teavm.model.MethodReference; -import org.teavm.model.Program; import org.teavm.model.ValueType; -import org.teavm.model.Variable; -import org.teavm.model.util.TypeInferer; -import org.teavm.model.util.VariableType; import org.teavm.wasm.model.WasmFunction; import org.teavm.wasm.model.WasmLocal; @@ -48,31 +44,13 @@ public class WasmGenerator { public WasmFunction generate(MethodReference methodReference) { ClassHolder cls = classSource.get(methodReference.getClassName()); MethodHolder method = cls.getMethod(methodReference.getDescriptor()); - Program program = method.getProgram(); RegularMethodNode methodAst = decompiler.decompileRegular(method); - TypeInferer inferer = new TypeInferer(); - inferer.inferTypes(program, methodReference); - - IntegerArray variableRepresentatives = new IntegerArray(methodAst.getVariables().size()); - for (int i = 0; i < program.variableCount(); ++i) { - Variable var = program.variableAt(i); - if (var.getRegister() < 0 || inferer.typeOf(i) == null) { - continue; - } - while (variableRepresentatives.size() <= var.getRegister()) { - variableRepresentatives.add(-1); - } - if (variableRepresentatives.get(var.getRegister()) < 0) { - variableRepresentatives.set(var.getRegister(), i); - } - } - WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference)); int firstVariable = method.hasModifier(ElementModifier.STATIC) ? 1 : 0; for (int i = firstVariable; i < methodAst.getVariables().size(); ++i) { - VariableType type = inferer.typeOf(variableRepresentatives.get(i)); - function.add(new WasmLocal(WasmGeneratorUtil.mapType(type))); + VariableNode variable = methodAst.getVariables().get(i); + function.add(new WasmLocal(WasmGeneratorUtil.mapType(variable.getType()))); } for (int i = firstVariable; i <= methodReference.parameterCount(); ++i) {