Add variables and variable types to AST. Use types to properly render variables in WASM

This commit is contained in:
Alexey Andreev 2016-08-18 23:12:27 +03:00
parent fc2c6b9e07
commit ca874d178d
11 changed files with 144 additions and 61 deletions

View File

@ -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<AsyncMethodPart> body = new ArrayList<>();
private List<Integer> variables = new ArrayList<>();
private List<Set<String>> parameterDebugNames = new ArrayList<>();
private List<VariableNode> variables = new ArrayList<>();
public AsyncMethodNode(MethodReference reference) {
super(reference);
@ -37,15 +33,19 @@ public class AsyncMethodNode extends MethodNode {
return body;
}
public List<Integer> getVariables() {
public List<VariableNode> getVariables() {
return variables;
}
@Override
public List<Set<String>> 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);

View File

@ -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;

View File

@ -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<Integer> variables = new ArrayList<>();
private List<Set<String>> parameterDebugNames = new ArrayList<>();
private List<VariableNode> variables = new ArrayList<>();
public RegularMethodNode(MethodReference reference) {
super(reference);
@ -37,13 +37,16 @@ public class RegularMethodNode extends MethodNode {
this.body = body;
}
public List<Integer> getVariables() {
public List<VariableNode> getVariables() {
return variables;
}
@Override
public List<Set<String>> getParameterDebugNames() {
return parameterDebugNames;
return variables.subList(0, getReference().parameterCount())
.stream()
.map(VariableNode::getDebugNames)
.collect(Collectors.toList());
}
@Override

View File

@ -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<String> 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<String> getDebugNames() {
return debugNames;
}
}

View File

@ -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()));

View File

@ -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);
}
}

View File

@ -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<VariableNode> reorderedVariables = new ArrayList<>();
int lastIndex;
UnusedVariableEliminator(int parameterCount, List<Integer> variables) {
UnusedVariableEliminator(int parameterCount, List<VariableNode> 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<VariableNode> 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;
}

View File

@ -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();

View File

@ -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<String> variableNames = new ArrayList<>();
for (int i = ref.parameterCount() + 1; i < variableCount; ++i) {

View File

@ -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, "<clinit>", void.class), null).use();
dependencyChecker.linkField(new FieldReference("java.lang.Object", "monitor"), null);
}
@Override

View File

@ -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) {