Add WASM s-expr emitter

This commit is contained in:
Alexey Andreev 2016-07-28 17:35:17 +03:00
parent 1484e970dd
commit e5356fae27
49 changed files with 913 additions and 78 deletions

View File

@ -20,10 +20,6 @@ import java.util.*;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.parsing.ClassDateProvider; import org.teavm.parsing.ClassDateProvider;
/**
*
* @author Alexey Andreev
*/
public class DiskCachedClassHolderSource implements ClassHolderSource { public class DiskCachedClassHolderSource implements ClassHolderSource {
private static AccessLevel[] accessLevels = AccessLevel.values(); private static AccessLevel[] accessLevels = AccessLevel.values();
private static ElementModifier[] elementModifiers = ElementModifier.values(); private static ElementModifier[] elementModifiers = ElementModifier.values();
@ -31,7 +27,7 @@ public class DiskCachedClassHolderSource implements ClassHolderSource {
private SymbolTable symbolTable; private SymbolTable symbolTable;
private ClassHolderSource innerSource; private ClassHolderSource innerSource;
private ClassDateProvider classDateProvider; private ClassDateProvider classDateProvider;
private Map<String, Item> cache = new HashMap<>(); private Map<String, Item> cache = new LinkedHashMap<>();
private Set<String> newClasses = new HashSet<>(); private Set<String> newClasses = new HashSet<>();
private ProgramIO programIO; private ProgramIO programIO;

View File

@ -17,16 +17,9 @@ package org.teavm.common;
import java.util.*; import java.util.*;
/**
*
* @author Alexey Andreev
*
* @param <T> which type this mapper takes.
* @param <R> which type this mapper produces.
*/
public class CachedMapper<T, R> implements Mapper<T, R> { public class CachedMapper<T, R> implements Mapper<T, R> {
private Mapper<T, R> innerMapper; private Mapper<T, R> innerMapper;
private Map<T, Wrapper<R>> cache = new HashMap<>(); private Map<T, Wrapper<R>> cache = new LinkedHashMap<>();
private List<KeyListener<T>> keyListeners = new ArrayList<>(); private List<KeyListener<T>> keyListeners = new ArrayList<>();
private static class Wrapper<S> { private static class Wrapper<S> {

View File

@ -17,7 +17,7 @@ package org.teavm.dependency;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
@ -30,16 +30,12 @@ import org.teavm.model.MethodHolder;
import org.teavm.model.util.ModelUtils; import org.teavm.model.util.ModelUtils;
import org.teavm.optimization.UnreachableBasicBlockEliminator; import org.teavm.optimization.UnreachableBasicBlockEliminator;
/**
*
* @author Alexey Andreev
*/
class DependencyClassSource implements ClassHolderSource { class DependencyClassSource implements ClassHolderSource {
private ClassReaderSource innerSource; private ClassReaderSource innerSource;
private Diagnostics diagnostics; private Diagnostics diagnostics;
private Map<String, ClassHolder> generatedClasses = new HashMap<>(); private Map<String, ClassHolder> generatedClasses = new LinkedHashMap<>();
private List<ClassHolderTransformer> transformers = new ArrayList<>(); private List<ClassHolderTransformer> transformers = new ArrayList<>();
private Map<String, ClassHolder> cache = new HashMap<>(); private Map<String, ClassHolder> cache = new LinkedHashMap<>();
public DependencyClassSource(ClassReaderSource innerSource, Diagnostics diagnostics) { public DependencyClassSource(ClassReaderSource innerSource, Diagnostics diagnostics) {
this.innerSource = innerSource; this.innerSource = innerSource;

View File

@ -18,10 +18,6 @@ package org.teavm.model;
import org.teavm.model.util.ModelUtils; import org.teavm.model.util.ModelUtils;
import org.teavm.resource.MapperClassHolderSource; import org.teavm.resource.MapperClassHolderSource;
/**
*
* @author Alexey Andreev
*/
public class CopyClassHolderSource implements ClassHolderSource { public class CopyClassHolderSource implements ClassHolderSource {
private ClassReaderSource innerSource; private ClassReaderSource innerSource;
private MapperClassHolderSource mapperSource = new MapperClassHolderSource(this::copyClass); private MapperClassHolderSource mapperSource = new MapperClassHolderSource(this::copyClass);

View File

@ -15,9 +15,5 @@
*/ */
package org.teavm.model; package org.teavm.model;
/**
*
* @author Alexey Andreev
*/
public interface ListableClassHolderSource extends ClassHolderSource, ListableClassReaderSource { public interface ListableClassHolderSource extends ClassHolderSource, ListableClassReaderSource {
} }

View File

@ -15,16 +15,12 @@
*/ */
package org.teavm.model; package org.teavm.model;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
*
* @author Alexey Andreev
*/
public class MutableClassHolderSource implements ListableClassHolderSource { public class MutableClassHolderSource implements ListableClassHolderSource {
private ConcurrentMap<String, ClassHolder> classes = new ConcurrentHashMap<>(); private Map<String, ClassHolder> classes = new LinkedHashMap<>();
@Override @Override
public Set<String> getClassNames() { public Set<String> getClassNames() {

View File

@ -15,14 +15,14 @@
*/ */
package org.teavm.model; package org.teavm.model;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.teavm.optimization.GlobalValueNumbering; import org.teavm.optimization.GlobalValueNumbering;
import org.teavm.optimization.UnusedVariableElimination; import org.teavm.optimization.UnusedVariableElimination;
public class PreOptimizingClassHolderSource implements ClassHolderSource { public class PreOptimizingClassHolderSource implements ClassHolderSource {
private ClassHolderSource innerClassSource; private ClassHolderSource innerClassSource;
private Map<String, ClassHolder> cache = new HashMap<>(); private Map<String, ClassHolder> cache = new LinkedHashMap<>();
public PreOptimizingClassHolderSource(ClassHolderSource innerClassSource) { public PreOptimizingClassHolderSource(ClassHolderSource innerClassSource) {
this.innerClassSource = innerClassSource; this.innerClassSource = innerClassSource;

View File

@ -22,10 +22,6 @@ import org.teavm.resource.ClasspathResourceReader;
import org.teavm.resource.MapperClassHolderSource; import org.teavm.resource.MapperClassHolderSource;
import org.teavm.resource.ResourceClassHolderMapper; import org.teavm.resource.ResourceClassHolderMapper;
/**
*
* @author Alexey Andreev
*/
public class ClasspathClassHolderSource implements ClassHolderSource, ClassDateProvider { public class ClasspathClassHolderSource implements ClassHolderSource, ClassDateProvider {
private MapperClassHolderSource innerClassSource; private MapperClassHolderSource innerClassSource;
private ClasspathResourceMapper classPathMapper; private ClasspathResourceMapper classPathMapper;

View File

@ -20,10 +20,6 @@ import org.teavm.common.Mapper;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource; import org.teavm.model.ClassHolderSource;
/**
*
* @author Alexey Andreev
*/
public class MapperClassHolderSource implements ClassHolderSource { public class MapperClassHolderSource implements ClassHolderSource {
private Mapper<String, ClassHolder> mapper; private Mapper<String, ClassHolder> mapper;

View File

@ -15,6 +15,8 @@
*/ */
package org.teavm.wasm; package org.teavm.wasm;
import org.teavm.wasm.runtime.WasmRuntime;
public final class Example { public final class Example {
private Example() { private Example() {
} }
@ -27,5 +29,6 @@ public final class Example {
a = b; a = b;
b = c; b = c;
} }
WasmRuntime.print(a);
} }
} }

View File

@ -61,29 +61,31 @@ import org.teavm.ast.VariableExpr;
import org.teavm.ast.WhileStatement; import org.teavm.ast.WhileStatement;
import org.teavm.wasm.model.WasmFunction; import org.teavm.wasm.model.WasmFunction;
import org.teavm.wasm.model.WasmLocal; import org.teavm.wasm.model.WasmLocal;
import org.teavm.wasm.model.expression.WasmAssignment;
import org.teavm.wasm.model.expression.WasmBlock; import org.teavm.wasm.model.expression.WasmBlock;
import org.teavm.wasm.model.expression.WasmBranch; import org.teavm.wasm.model.expression.WasmBranch;
import org.teavm.wasm.model.expression.WasmBreak; import org.teavm.wasm.model.expression.WasmBreak;
import org.teavm.wasm.model.expression.WasmCall; import org.teavm.wasm.model.expression.WasmCall;
import org.teavm.wasm.model.expression.WasmConditional; import org.teavm.wasm.model.expression.WasmConditional;
import org.teavm.wasm.model.expression.WasmConversion; import org.teavm.wasm.model.expression.WasmConversion;
import org.teavm.wasm.model.expression.WasmDrop;
import org.teavm.wasm.model.expression.WasmExpression; import org.teavm.wasm.model.expression.WasmExpression;
import org.teavm.wasm.model.expression.WasmFloat32Constant; import org.teavm.wasm.model.expression.WasmFloat32Constant;
import org.teavm.wasm.model.expression.WasmFloat64Constant; import org.teavm.wasm.model.expression.WasmFloat64Constant;
import org.teavm.wasm.model.expression.WasmFloatBinary; import org.teavm.wasm.model.expression.WasmFloatBinary;
import org.teavm.wasm.model.expression.WasmFloatBinaryOperation; import org.teavm.wasm.model.expression.WasmFloatBinaryOperation;
import org.teavm.wasm.model.expression.WasmFloatType; import org.teavm.wasm.model.expression.WasmFloatType;
import org.teavm.wasm.model.expression.WasmGetLocal;
import org.teavm.wasm.model.expression.WasmInt32Constant; import org.teavm.wasm.model.expression.WasmInt32Constant;
import org.teavm.wasm.model.expression.WasmInt64Constant; import org.teavm.wasm.model.expression.WasmInt64Constant;
import org.teavm.wasm.model.expression.WasmIntBinary; import org.teavm.wasm.model.expression.WasmIntBinary;
import org.teavm.wasm.model.expression.WasmIntBinaryOperation; import org.teavm.wasm.model.expression.WasmIntBinaryOperation;
import org.teavm.wasm.model.expression.WasmIntType; import org.teavm.wasm.model.expression.WasmIntType;
import org.teavm.wasm.model.expression.WasmLocalReference;
import org.teavm.wasm.model.expression.WasmReturn; import org.teavm.wasm.model.expression.WasmReturn;
import org.teavm.wasm.model.expression.WasmSetLocal;
import org.teavm.wasm.model.expression.WasmSwitch; import org.teavm.wasm.model.expression.WasmSwitch;
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private int firstVariable;
private WasmFunction function; private WasmFunction function;
private IdentifiedStatement currentContinueTarget; private IdentifiedStatement currentContinueTarget;
private IdentifiedStatement currentBreakTarget; private IdentifiedStatement currentBreakTarget;
@ -92,8 +94,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private Set<WasmBlock> usedBlocks = new HashSet<>(); private Set<WasmBlock> usedBlocks = new HashSet<>();
WasmExpression result; WasmExpression result;
public WasmGenerationVisitor(WasmFunction function) { public WasmGenerationVisitor(WasmFunction function, int firstVariable) {
this.function = function; this.function = function;
this.firstVariable = firstVariable;
} }
@Override @Override
@ -331,11 +334,14 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
@Override @Override
public void visit(AssignmentStatement statement) { public void visit(AssignmentStatement statement) {
Expr left = statement.getLeftValue(); Expr left = statement.getLeftValue();
if (left instanceof VariableExpr) { if (left == null) {
VariableExpr varExpr = (VariableExpr) left;
WasmLocal local = function.getLocalVariables().get(varExpr.getIndex());
statement.getRightValue().acceptVisitor(this); statement.getRightValue().acceptVisitor(this);
result = new WasmAssignment(local, result); result = new WasmDrop(result);
} else if (left instanceof VariableExpr) {
VariableExpr varExpr = (VariableExpr) left;
WasmLocal local = function.getLocalVariables().get(varExpr.getIndex() - firstVariable);
statement.getRightValue().acceptVisitor(this);
result = new WasmSetLocal(local, result);
} else { } else {
throw new UnsupportedOperationException("This expression is not supported yet"); throw new UnsupportedOperationException("This expression is not supported yet");
} }
@ -396,7 +402,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
@Override @Override
public void visit(VariableExpr expr) { public void visit(VariableExpr expr) {
result = new WasmLocalReference(function.getLocalVariables().get(expr.getIndex())); result = new WasmGetLocal(function.getLocalVariables().get(expr.getIndex() - firstVariable));
} }
@Override @Override
@ -457,6 +463,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
currentBreakTarget = statement; currentBreakTarget = statement;
currentContinueTarget = statement; currentContinueTarget = statement;
if (statement.getCondition() != null) {
statement.getCondition().acceptVisitor(this);
loop.getBody().add(new WasmBranch(result, wrapper));
usedBlocks.add(wrapper);
}
for (Statement part : statement.getBody()) { for (Statement part : statement.getBody()) {
part.acceptVisitor(this); part.acceptVisitor(this);
loop.getBody().add(result); loop.getBody().add(result);

View File

@ -19,6 +19,7 @@ import org.teavm.ast.RegularMethodNode;
import org.teavm.ast.decompilation.Decompiler; import org.teavm.ast.decompilation.Decompiler;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource; import org.teavm.model.ClassHolderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodHolder; import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
@ -47,20 +48,21 @@ public class WasmGenerator {
inferer.inferTypes(program, methodReference); inferer.inferTypes(program, methodReference);
WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference)); WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference));
for (int i = 0; i < methodAst.getVariables().size(); ++i) { int firstVariable = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
for (int i = firstVariable; i < methodAst.getVariables().size(); ++i) {
int varIndex = methodAst.getVariables().get(i); int varIndex = methodAst.getVariables().get(i);
VariableType type = inferer.typeOf(varIndex); VariableType type = inferer.typeOf(varIndex);
function.add(new WasmLocal(WasmGeneratorUtil.mapType(type))); function.add(new WasmLocal(WasmGeneratorUtil.mapType(type)));
} }
for (int i = 0; i <= methodReference.parameterCount(); ++i) { for (int i = firstVariable; i <= methodReference.parameterCount(); ++i) {
function.getParameters().add(function.getLocalVariables().get(i).getType()); function.getParameters().add(function.getLocalVariables().get(i - firstVariable).getType());
} }
if (methodReference.getReturnType() != ValueType.VOID) { if (methodReference.getReturnType() != ValueType.VOID) {
function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType())); function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType()));
} }
WasmGenerationVisitor visitor = new WasmGenerationVisitor(function); WasmGenerationVisitor visitor = new WasmGenerationVisitor(function, firstVariable);
methodAst.getBody().acceptVisitor(visitor); methodAst.getBody().acceptVisitor(visitor);
function.getBody().add(visitor.result); function.getBody().add(visitor.result);

View File

@ -25,7 +25,7 @@ public final class WasmMangling {
} }
public static String mangleMethod(MethodReference method) { public static String mangleMethod(MethodReference method) {
StringBuilder sb = new StringBuilder("method$" + mangleString(method.getClassName()) + "$"); StringBuilder sb = new StringBuilder("method_" + mangleString(method.getClassName()) + "_");
String name = mangleString(method.getName()); String name = mangleString(method.getName());
sb.append(mangleType(method.getReturnType())); sb.append(mangleType(method.getReturnType()));
sb.append(name.length() + "_" + name); sb.append(name.length() + "_" + name);
@ -41,8 +41,6 @@ public final class WasmMangling {
char c = string.charAt(i); char c = string.charAt(i);
switch (c) { switch (c) {
case '$': case '$':
case '.':
case '-':
sb.append(c); sb.append(c);
break; break;
case '_': case '_':

View File

@ -37,4 +37,9 @@ public class WasmBlock extends WasmExpression {
public List<WasmExpression> getBody() { public List<WasmExpression> getBody() {
return body; return body;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -54,4 +54,9 @@ public class WasmBranch extends WasmExpression {
public void setResult(WasmExpression result) { public void setResult(WasmExpression result) {
this.result = result; this.result = result;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -42,4 +42,9 @@ public class WasmBreak extends WasmExpression {
public void setResult(WasmExpression result) { public void setResult(WasmExpression result) {
this.result = result; this.result = result;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -54,4 +54,9 @@ public class WasmCall extends WasmExpression {
public void setImported(boolean imported) { public void setImported(boolean imported) {
this.imported = imported; this.imported = imported;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -43,4 +43,9 @@ public class WasmConditional extends WasmExpression {
public WasmBlock getElseBlock() { public WasmBlock getElseBlock() {
return elseBlock; return elseBlock;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -68,4 +68,9 @@ public class WasmConversion extends WasmExpression {
Objects.requireNonNull(operand); Objects.requireNonNull(operand);
this.operand = operand; this.operand = operand;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -33,4 +33,9 @@ public class WasmDrop extends WasmExpression {
Objects.requireNonNull(operand); Objects.requireNonNull(operand);
this.operand = operand; this.operand = operand;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -18,4 +18,6 @@ package org.teavm.wasm.model.expression;
public abstract class WasmExpression { public abstract class WasmExpression {
WasmExpression() { WasmExpression() {
} }
public abstract void acceptVisitor(WasmExpressionVisitor visitor);
} }

View File

@ -0,0 +1,76 @@
/*
* 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.wasm.model.expression;
public interface WasmExpressionVisitor {
void visit(WasmBlock expression);
void visit(WasmBranch expression);
void visit(WasmBreak expression);
void visit(WasmSwitch expression);
void visit(WasmConditional expression);
void visit(WasmReturn expression);
void visit(WasmUnreachable expression);
void visit(WasmInt32Constant expression);
void visit(WasmInt64Constant expression);
void visit(WasmFloat32Constant expression);
void visit(WasmFloat64Constant expression);
void visit(WasmGetLocal expression);
void visit(WasmSetLocal expression);
void visit(WasmIntBinary expression);
void visit(WasmFloatBinary expression);
void visit(WasmIntUnary expression);
void visit(WasmFloatUnary expression);
void visit(WasmConversion expression);
void visit(WasmCall expression);
void visit(WasmIndirectCall expression);
void visit(WasmDrop expression);
void visit(WasmLoadInt32 expression);
void visit(WasmLoadInt64 expression);
void visit(WasmLoadFloat32 expression);
void visit(WasmLoadFloat64 expression);
void visit(WasmStoreInt32 expression);
void visit(WasmStoreInt64 expression);
void visit(WasmStoreFloat32 expression);
void visit(WasmStoreFloat64 expression);
}

View File

@ -29,4 +29,9 @@ public class WasmFloat32Constant extends WasmExpression {
public void setValue(float value) { public void setValue(float value) {
this.value = value; this.value = value;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -29,4 +29,9 @@ public class WasmFloat64Constant extends WasmExpression {
public void setValue(double value) { public void setValue(double value) {
this.value = value; this.value = value;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -70,4 +70,9 @@ public class WasmFloatBinary extends WasmExpression {
Objects.requireNonNull(second); Objects.requireNonNull(second);
this.second = second; this.second = second;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -25,5 +25,7 @@ public enum WasmFloatBinaryOperation {
LT, LT,
LE, LE,
GT, GT,
GE GE,
MIN,
MAX
} }

View File

@ -57,4 +57,9 @@ public class WasmFloatUnary extends WasmExpression {
Objects.requireNonNull(operand); Objects.requireNonNull(operand);
this.operand = operand; this.operand = operand;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -23,13 +23,5 @@ public enum WasmFloatUnaryOperation {
FLOOR, FLOOR,
TRUNC, TRUNC,
NEAREST, NEAREST,
MIN, SQRT
MAX,
SQRT,
EQ,
NE,
LT,
LE,
GT,
GE
} }

View File

@ -18,10 +18,10 @@ package org.teavm.wasm.model.expression;
import java.util.Objects; import java.util.Objects;
import org.teavm.wasm.model.WasmLocal; import org.teavm.wasm.model.WasmLocal;
public class WasmLocalReference extends WasmExpression { public class WasmGetLocal extends WasmExpression {
private WasmLocal local; private WasmLocal local;
public WasmLocalReference(WasmLocal local) { public WasmGetLocal(WasmLocal local) {
Objects.requireNonNull(local); Objects.requireNonNull(local);
this.local = local; this.local = local;
} }
@ -34,4 +34,9 @@ public class WasmLocalReference extends WasmExpression {
Objects.requireNonNull(local); Objects.requireNonNull(local);
this.local = local; this.local = local;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -15,15 +15,19 @@
*/ */
package org.teavm.wasm.model.expression; package org.teavm.wasm.model.expression;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public class WasmIndirectCall extends WasmExpression { public class WasmIndirectCall extends WasmExpression {
private String typeName;
private WasmExpression selector; private WasmExpression selector;
private List<WasmExpression> arguments; private List<WasmExpression> arguments = new ArrayList<>();
public WasmIndirectCall(WasmExpression selector) { public WasmIndirectCall(String typeName, WasmExpression selector) {
Objects.requireNonNull(typeName);
Objects.requireNonNull(selector); Objects.requireNonNull(selector);
this.typeName = typeName;
this.selector = selector; this.selector = selector;
} }
@ -36,7 +40,21 @@ public class WasmIndirectCall extends WasmExpression {
this.selector = selector; this.selector = selector;
} }
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
Objects.requireNonNull(typeName);
this.typeName = typeName;
}
public List<WasmExpression> getArguments() { public List<WasmExpression> getArguments() {
return arguments; return arguments;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -29,4 +29,9 @@ public class WasmInt32Constant extends WasmExpression {
public void setValue(int value) { public void setValue(int value) {
this.value = value; this.value = value;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -29,4 +29,9 @@ public class WasmInt64Constant extends WasmExpression {
public void setValue(long value) { public void setValue(long value) {
this.value = value; this.value = value;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -70,4 +70,9 @@ public class WasmIntBinary extends WasmExpression {
Objects.requireNonNull(second); Objects.requireNonNull(second);
this.second = second; this.second = second;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -57,4 +57,9 @@ public class WasmIntUnary extends WasmExpression {
Objects.requireNonNull(operand); Objects.requireNonNull(operand);
this.operand = operand; this.operand = operand;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -43,4 +43,9 @@ public class WasmLoadFloat32 extends WasmExpression {
Objects.requireNonNull(index); Objects.requireNonNull(index);
this.index = index; this.index = index;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -43,4 +43,9 @@ public class WasmLoadFloat64 extends WasmExpression {
Objects.requireNonNull(index); Objects.requireNonNull(index);
this.index = index; this.index = index;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -55,4 +55,9 @@ public class WasmLoadInt32 extends WasmExpression {
Objects.requireNonNull(convertFrom); Objects.requireNonNull(convertFrom);
this.convertFrom = convertFrom; this.convertFrom = convertFrom;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -55,4 +55,9 @@ public class WasmLoadInt64 extends WasmExpression {
Objects.requireNonNull(convertFrom); Objects.requireNonNull(convertFrom);
this.convertFrom = convertFrom; this.convertFrom = convertFrom;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -33,4 +33,9 @@ public class WasmReturn extends WasmExpression {
public void setValue(WasmExpression value) { public void setValue(WasmExpression value) {
this.value = value; this.value = value;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -18,11 +18,11 @@ package org.teavm.wasm.model.expression;
import java.util.Objects; import java.util.Objects;
import org.teavm.wasm.model.WasmLocal; import org.teavm.wasm.model.WasmLocal;
public class WasmAssignment extends WasmExpression { public class WasmSetLocal extends WasmExpression {
private WasmLocal local; private WasmLocal local;
private WasmExpression value; private WasmExpression value;
public WasmAssignment(WasmLocal local, WasmExpression value) { public WasmSetLocal(WasmLocal local, WasmExpression value) {
Objects.requireNonNull(local); Objects.requireNonNull(local);
Objects.requireNonNull(value); Objects.requireNonNull(value);
this.local = local; this.local = local;
@ -46,4 +46,9 @@ public class WasmAssignment extends WasmExpression {
Objects.requireNonNull(value); Objects.requireNonNull(value);
this.value = value; this.value = value;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -55,4 +55,9 @@ public class WasmStoreFloat32 extends WasmExpression {
Objects.requireNonNull(value); Objects.requireNonNull(value);
this.value = value; this.value = value;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -55,4 +55,9 @@ public class WasmStoreFloat64 extends WasmExpression {
Objects.requireNonNull(value); Objects.requireNonNull(value);
this.value = value; this.value = value;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -68,4 +68,9 @@ public class WasmStoreInt32 extends WasmExpression {
Objects.requireNonNull(convertTo); Objects.requireNonNull(convertTo);
this.convertTo = convertTo; this.convertTo = convertTo;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -68,4 +68,9 @@ public class WasmStoreInt64 extends WasmExpression {
Objects.requireNonNull(convertTo); Objects.requireNonNull(convertTo);
this.convertTo = convertTo; this.convertTo = convertTo;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -50,4 +50,9 @@ public class WasmSwitch extends WasmExpression {
public List<WasmBlock> getTargets() { public List<WasmBlock> getTargets() {
return targets; return targets;
} }
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
} }

View File

@ -16,8 +16,11 @@
package org.teavm.wasm.model.expression; package org.teavm.wasm.model.expression;
public class WasmUnreachable extends WasmExpression { public class WasmUnreachable extends WasmExpression {
public static final WasmUnreachable INSTANCE = new WasmUnreachable(); public WasmUnreachable() {
}
private WasmUnreachable() { @Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
} }
} }

View File

@ -0,0 +1,56 @@
/*
* 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.wasm.render;
import java.util.List;
import org.teavm.wasm.model.WasmFunction;
import org.teavm.wasm.model.WasmLocal;
import org.teavm.wasm.model.WasmType;
import org.teavm.wasm.model.expression.WasmExpression;
public class WasmRenderer {
private WasmRenderingVisitor visitor = new WasmRenderingVisitor();
public void render(WasmFunction function) {
visitor.open().append("func " + function.getName());
for (WasmType type : function.getParameters()) {
visitor.append(" ").open().append("param ").append(type).close();
}
if (function.getResult() != null) {
visitor.append(" ").open().append("result ").append(function.getResult()).close();
}
int firstLocalVariable = function.getParameters().size();
if (firstLocalVariable > function.getLocalVariables().size()) {
visitor.open().append("local");
List<WasmLocal> locals = function.getLocalVariables().subList(firstLocalVariable,
function.getLocalVariables().size());
for (WasmLocal local : locals) {
visitor.append(" " + local.getType());
}
visitor.close();
}
for (WasmExpression part : function.getBody()) {
visitor.line(part);
}
visitor.close().lf().lf();
}
@Override
public String toString() {
return visitor.sb.toString();
}
}

View File

@ -0,0 +1,569 @@
/*
* 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.wasm.render;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.teavm.wasm.model.WasmLocal;
import org.teavm.wasm.model.WasmType;
import org.teavm.wasm.model.expression.WasmBlock;
import org.teavm.wasm.model.expression.WasmBranch;
import org.teavm.wasm.model.expression.WasmBreak;
import org.teavm.wasm.model.expression.WasmCall;
import org.teavm.wasm.model.expression.WasmConditional;
import org.teavm.wasm.model.expression.WasmConversion;
import org.teavm.wasm.model.expression.WasmDrop;
import org.teavm.wasm.model.expression.WasmExpression;
import org.teavm.wasm.model.expression.WasmExpressionVisitor;
import org.teavm.wasm.model.expression.WasmFloat32Constant;
import org.teavm.wasm.model.expression.WasmFloat64Constant;
import org.teavm.wasm.model.expression.WasmFloatBinary;
import org.teavm.wasm.model.expression.WasmFloatBinaryOperation;
import org.teavm.wasm.model.expression.WasmFloatType;
import org.teavm.wasm.model.expression.WasmFloatUnary;
import org.teavm.wasm.model.expression.WasmFloatUnaryOperation;
import org.teavm.wasm.model.expression.WasmGetLocal;
import org.teavm.wasm.model.expression.WasmIndirectCall;
import org.teavm.wasm.model.expression.WasmInt32Constant;
import org.teavm.wasm.model.expression.WasmInt64Constant;
import org.teavm.wasm.model.expression.WasmIntBinary;
import org.teavm.wasm.model.expression.WasmIntBinaryOperation;
import org.teavm.wasm.model.expression.WasmIntType;
import org.teavm.wasm.model.expression.WasmIntUnary;
import org.teavm.wasm.model.expression.WasmIntUnaryOperation;
import org.teavm.wasm.model.expression.WasmLoadFloat32;
import org.teavm.wasm.model.expression.WasmLoadFloat64;
import org.teavm.wasm.model.expression.WasmLoadInt32;
import org.teavm.wasm.model.expression.WasmLoadInt64;
import org.teavm.wasm.model.expression.WasmReturn;
import org.teavm.wasm.model.expression.WasmSetLocal;
import org.teavm.wasm.model.expression.WasmStoreFloat32;
import org.teavm.wasm.model.expression.WasmStoreFloat64;
import org.teavm.wasm.model.expression.WasmStoreInt32;
import org.teavm.wasm.model.expression.WasmStoreInt64;
import org.teavm.wasm.model.expression.WasmSwitch;
import org.teavm.wasm.model.expression.WasmUnreachable;
class WasmRenderingVisitor implements WasmExpressionVisitor {
private Set<String> usedIdentifiers = new HashSet<>();
StringBuilder sb = new StringBuilder();
private Map<WasmBlock, String> blockIdentifiers = new HashMap<>();
private Map<WasmLocal, String> localIdentifiers = new HashMap<>();
private int indentLevel;
private boolean lfDeferred;
void clear() {
blockIdentifiers.clear();
localIdentifiers.clear();
usedIdentifiers.clear();
}
WasmRenderingVisitor append(String text) {
if (lfDeferred) {
lfDeferred = false;
sb.append("\n");
for (int i = 0; i < indentLevel; ++i) {
sb.append(" ");
}
}
sb.append(text);
return this;
}
WasmRenderingVisitor append(WasmType type) {
return append(type(type));
}
WasmRenderingVisitor append(WasmExpression expression) {
expression.acceptVisitor(this);
return this;
}
WasmRenderingVisitor line(WasmExpression expression) {
return lf().append(expression);
}
WasmRenderingVisitor indent() {
indentLevel++;
return this;
}
WasmRenderingVisitor outdent() {
indentLevel--;
return this;
}
WasmRenderingVisitor lf() {
if (lfDeferred) {
sb.append("\n");
}
lfDeferred = true;
return this;
}
WasmRenderingVisitor open() {
append("(").indent();
return this;
}
WasmRenderingVisitor close() {
outdent().append(")");
return this;
}
@Override
public void visit(WasmBlock expression) {
renderBlock(expression, expression.isLoop() ? "loop" : "block");
}
private void renderBlock(WasmBlock block, String name) {
String id = getIdentifier("@block");
blockIdentifiers.put(block, id);
open().append(name + " " + id);
for (WasmExpression part : block.getBody()) {
line(part);
}
close();
}
@Override
public void visit(WasmBranch expression) {
String id = blockIdentifiers.get(expression.getTarget());
open().append("br_if " + id);
if (expression.getResult() != null) {
line(expression.getResult());
}
line(expression.getCondition());
close();
}
@Override
public void visit(WasmBreak expression) {
String id = blockIdentifiers.get(expression.getTarget());
open().append("br ").append(id);
if (expression.getResult() != null) {
line(expression.getResult());
}
close();
}
@Override
public void visit(WasmSwitch expression) {
open().append("br_table ");
for (WasmBlock target : expression.getTargets()) {
append(blockIdentifiers.get(target)).append(" ");
}
append(blockIdentifiers.get(expression.getDefaultTarget()));
line(expression.getSelector());
close();
}
@Override
public void visit(WasmConditional expression) {
open().append("if");
line(expression.getCondition());
lf();
renderBlock(expression.getThenBlock(), "then");
lf();
renderBlock(expression.getThenBlock(), "else");
close();
}
@Override
public void visit(WasmReturn expression) {
open().append("return");
if (expression.getValue() != null) {
line(expression.getValue());
}
close();
}
@Override
public void visit(WasmUnreachable expression) {
open().append("unreachable").close();
}
@Override
public void visit(WasmInt32Constant expression) {
open().append("i32.const " + expression.getValue()).close();
}
@Override
public void visit(WasmInt64Constant expression) {
open().append("i64.const " + expression.getValue()).close();
}
@Override
public void visit(WasmFloat32Constant expression) {
open().append("f32.const " + Float.toHexString(expression.getValue())).close();
}
@Override
public void visit(WasmFloat64Constant expression) {
open().append("f64.const " + Double.toHexString(expression.getValue())).close();
}
@Override
public void visit(WasmGetLocal expression) {
open().append("get_local " + asString(expression.getLocal())).close();
}
@Override
public void visit(WasmSetLocal expression) {
open().append("set_local " + asString(expression.getLocal())).line(expression.getValue()).close();
}
private String asString(WasmLocal local) {
return localIdentifiers.computeIfAbsent(local, l -> {
String suggested = l.getName() != null ? l.getName() : "@local" + local.getIndex();
return getIdentifier(suggested);
});
}
@Override
public void visit(WasmIntBinary expression) {
open().append(type(expression.getType()) + "." + operation(expression.getOperation()));
line(expression.getFirst());
line(expression.getSecond());
close();
}
@Override
public void visit(WasmFloatBinary expression) {
open().append(type(expression.getType()) + "." + operation(expression.getOperation()));
line(expression.getFirst());
line(expression.getSecond());
close();
}
@Override
public void visit(WasmIntUnary expression) {
open().append(type(expression.getType()) + "." + operation(expression.getOperation()));
line(expression.getOperand());
close();
}
@Override
public void visit(WasmFloatUnary expression) {
open().append(type(expression.getType()) + "." + operation(expression.getOperation()));
line(expression.getOperand());
close();
}
@Override
public void visit(WasmConversion expression) {
String name = null;
switch (expression.getSourceType()) {
case INT32:
switch (expression.getTargetType()) {
case INT32:
break;
case INT64:
name = expression.isSigned() ? "extend_s" : "extend_u";
break;
case FLOAT32:
case FLOAT64:
name = expression.isSigned() ? "convert_s" : "convert_u";
break;
}
break;
case INT64:
switch (expression.getTargetType()) {
case INT32:
name = "wrap";
break;
case INT64:
break;
case FLOAT32:
case FLOAT64:
name = expression.isSigned() ? "convert_s" : "convert_u";
break;
}
break;
case FLOAT32:
switch (expression.getTargetType()) {
case INT32:
case INT64:
name = expression.isSigned() ? "trunc_s" : "trunc_u";
break;
case FLOAT32:
break;
case FLOAT64:
name = "promote";
break;
}
break;
case FLOAT64:
switch (expression.getTargetType()) {
case INT32:
case INT64:
name = expression.isSigned() ? "trunc_s" : "trunc_u";
break;
case FLOAT32:
name = "demote";
break;
case FLOAT64:
break;
}
break;
}
if (name == null) {
append(expression.getOperand());
} else {
open().append(type(expression.getTargetType()) + "." + name + "/" + type(expression.getSourceType()));
line(expression.getOperand());
close();
}
}
@Override
public void visit(WasmCall expression) {
open().append(expression.isImported() ? "call_import" : "call").append(" " + expression.getFunctionName());
for (WasmExpression argument : expression.getArguments()) {
line(argument);
}
close();
}
@Override
public void visit(WasmIndirectCall expression) {
open().append("call_indirect").append(" " + expression.getTypeName());
line(expression.getSelector());
for (WasmExpression argument : expression.getArguments()) {
line(argument);
}
close();
}
@Override
public void visit(WasmDrop expression) {
open().append("drop").line(expression.getOperand()).close();
}
@Override
public void visit(WasmLoadInt32 expression) {
}
@Override
public void visit(WasmLoadInt64 expression) {
}
@Override
public void visit(WasmLoadFloat32 expression) {
}
@Override
public void visit(WasmLoadFloat64 expression) {
}
@Override
public void visit(WasmStoreInt32 expression) {
}
@Override
public void visit(WasmStoreInt64 expression) {
}
@Override
public void visit(WasmStoreFloat32 expression) {
}
@Override
public void visit(WasmStoreFloat64 expression) {
}
private String getIdentifier(String suggested) {
if (usedIdentifiers.add(suggested)) {
return suggested;
}
int index = 1;
while (true) {
String id = suggested + "#" + index;
if (usedIdentifiers.add(id)) {
return id;
}
++index;
}
}
private String type(WasmType type) {
switch (type) {
case INT32:
return "i32";
case INT64:
return "i64";
case FLOAT32:
return "f32";
case FLOAT64:
return "f64";
}
throw new AssertionError(type.toString());
}
private String type(WasmIntType type) {
switch (type) {
case INT32:
return "i32";
case INT64:
return "i64";
}
throw new AssertionError(type.toString());
}
private String type(WasmFloatType type) {
switch (type) {
case FLOAT32:
return "f32";
case FLOAT64:
return "f64";
}
throw new AssertionError(type.toString());
}
private String operation(WasmIntBinaryOperation operation) {
switch (operation) {
case ADD:
return "add";
case SUB:
return "sub";
case MUL:
return "mul";
case DIV_SIGNED:
return "div_s";
case DIV_UNSIGNED:
return "div_u";
case REM_SIGNED:
return "rem_s";
case REM_UNSIGNED:
return "rem_u";
case AND:
return "and";
case OR:
return "or";
case XOR:
return "xor";
case EQ:
return "eq";
case NE:
return "ne";
case GT_SIGNED:
return "gt_s";
case GT_UNSIGNED:
return "gt_u";
case GE_SIGNED:
return "ge_s";
case GE_UNSIGNED:
return "ge_u";
case LT_SIGNED:
return "lt_s";
case LT_UNSIGNED:
return "lt_u";
case LE_SIGNED:
return "le_s";
case LE_UNSIGNED:
return "le_u";
case SHL:
return "shl";
case SHR_SIGNED:
return "shr_s";
case SHR_UNSIGNED:
return "shr_u";
case ROTL:
return "rotl";
case ROTR:
return "rotr";
}
throw new AssertionError(operation.toString());
}
private String operation(WasmIntUnaryOperation operation) {
switch (operation) {
case CLZ:
return "clz";
case CTZ:
return "ctz";
case POPCNT:
return "popcnt";
}
throw new AssertionError(operation.toString());
}
private String operation(WasmFloatBinaryOperation operation) {
switch (operation) {
case ADD:
return "add";
case SUB:
return "sub";
case MUL:
return "mul";
case DIV:
return "div";
case EQ:
return "eq";
case NE:
return "ne";
case GT:
return "gt";
case GE:
return "ge";
case LT:
return "lt";
case LE:
return "le";
case MIN:
return "min";
case MAX:
return "max";
}
throw new AssertionError(operation.toString());
}
private String operation(WasmFloatUnaryOperation operation) {
switch (operation) {
case ABS:
return "abs";
case NEG:
return "neg";
case COPYSIGN:
break;
case CEIL:
return "ceil";
case FLOOR:
return "floor";
case TRUNC:
return "trunc";
case NEAREST:
return "nearest";
case SQRT:
return "sqrt";
}
throw new AssertionError(operation.toString());
}
}

View File

@ -42,4 +42,6 @@ public final class WasmRuntime {
public static double remainder(double a, double b) { public static double remainder(double a, double b) {
return a - (double) (long) (a / b) * b; return a - (double) (long) (a / b) * b;
} }
public static native void print(int a);
} }