mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 16:04:10 -08:00
Add variables and variable types to AST. Use types to properly render variables in WASM
This commit is contained in:
parent
fc2c6b9e07
commit
ca874d178d
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
51
core/src/main/java/org/teavm/ast/VariableNode.java
Normal file
51
core/src/main/java/org/teavm/ast/VariableNode.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
36
core/src/main/java/org/teavm/cache/AstIO.java
vendored
36
core/src/main/java/org/teavm/cache/AstIO.java
vendored
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user