diff --git a/core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java b/core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java index 86952801e..9f560dd52 100644 --- a/core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java +++ b/core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java @@ -20,10 +20,6 @@ import java.util.*; import org.teavm.model.*; import org.teavm.parsing.ClassDateProvider; -/** - * - * @author Alexey Andreev - */ public class DiskCachedClassHolderSource implements ClassHolderSource { private static AccessLevel[] accessLevels = AccessLevel.values(); private static ElementModifier[] elementModifiers = ElementModifier.values(); @@ -31,7 +27,7 @@ public class DiskCachedClassHolderSource implements ClassHolderSource { private SymbolTable symbolTable; private ClassHolderSource innerSource; private ClassDateProvider classDateProvider; - private Map cache = new HashMap<>(); + private Map cache = new LinkedHashMap<>(); private Set newClasses = new HashSet<>(); private ProgramIO programIO; diff --git a/core/src/main/java/org/teavm/common/CachedMapper.java b/core/src/main/java/org/teavm/common/CachedMapper.java index 027d43556..702131b47 100644 --- a/core/src/main/java/org/teavm/common/CachedMapper.java +++ b/core/src/main/java/org/teavm/common/CachedMapper.java @@ -17,16 +17,9 @@ package org.teavm.common; import java.util.*; -/** - * - * @author Alexey Andreev - * - * @param which type this mapper takes. - * @param which type this mapper produces. - */ public class CachedMapper implements Mapper { private Mapper innerMapper; - private Map> cache = new HashMap<>(); + private Map> cache = new LinkedHashMap<>(); private List> keyListeners = new ArrayList<>(); private static class Wrapper { diff --git a/core/src/main/java/org/teavm/dependency/DependencyClassSource.java b/core/src/main/java/org/teavm/dependency/DependencyClassSource.java index 9d55292c6..0bdcbb574 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyClassSource.java +++ b/core/src/main/java/org/teavm/dependency/DependencyClassSource.java @@ -17,7 +17,7 @@ package org.teavm.dependency; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.teavm.diagnostics.Diagnostics; @@ -30,16 +30,12 @@ import org.teavm.model.MethodHolder; import org.teavm.model.util.ModelUtils; import org.teavm.optimization.UnreachableBasicBlockEliminator; -/** - * - * @author Alexey Andreev - */ class DependencyClassSource implements ClassHolderSource { private ClassReaderSource innerSource; private Diagnostics diagnostics; - private Map generatedClasses = new HashMap<>(); + private Map generatedClasses = new LinkedHashMap<>(); private List transformers = new ArrayList<>(); - private Map cache = new HashMap<>(); + private Map cache = new LinkedHashMap<>(); public DependencyClassSource(ClassReaderSource innerSource, Diagnostics diagnostics) { this.innerSource = innerSource; diff --git a/core/src/main/java/org/teavm/model/CopyClassHolderSource.java b/core/src/main/java/org/teavm/model/CopyClassHolderSource.java index 289c2d5b8..c6421f25f 100644 --- a/core/src/main/java/org/teavm/model/CopyClassHolderSource.java +++ b/core/src/main/java/org/teavm/model/CopyClassHolderSource.java @@ -18,10 +18,6 @@ package org.teavm.model; import org.teavm.model.util.ModelUtils; import org.teavm.resource.MapperClassHolderSource; -/** - * - * @author Alexey Andreev - */ public class CopyClassHolderSource implements ClassHolderSource { private ClassReaderSource innerSource; private MapperClassHolderSource mapperSource = new MapperClassHolderSource(this::copyClass); diff --git a/core/src/main/java/org/teavm/model/ListableClassHolderSource.java b/core/src/main/java/org/teavm/model/ListableClassHolderSource.java index 173795616..c186db988 100644 --- a/core/src/main/java/org/teavm/model/ListableClassHolderSource.java +++ b/core/src/main/java/org/teavm/model/ListableClassHolderSource.java @@ -15,9 +15,5 @@ */ package org.teavm.model; -/** - * - * @author Alexey Andreev - */ public interface ListableClassHolderSource extends ClassHolderSource, ListableClassReaderSource { } diff --git a/core/src/main/java/org/teavm/model/MutableClassHolderSource.java b/core/src/main/java/org/teavm/model/MutableClassHolderSource.java index 39dbb6262..a5318bca6 100644 --- a/core/src/main/java/org/teavm/model/MutableClassHolderSource.java +++ b/core/src/main/java/org/teavm/model/MutableClassHolderSource.java @@ -15,16 +15,12 @@ */ package org.teavm.model; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -/** - * - * @author Alexey Andreev - */ public class MutableClassHolderSource implements ListableClassHolderSource { - private ConcurrentMap classes = new ConcurrentHashMap<>(); + private Map classes = new LinkedHashMap<>(); @Override public Set getClassNames() { diff --git a/core/src/main/java/org/teavm/model/PreOptimizingClassHolderSource.java b/core/src/main/java/org/teavm/model/PreOptimizingClassHolderSource.java index 99538be98..1e200542b 100644 --- a/core/src/main/java/org/teavm/model/PreOptimizingClassHolderSource.java +++ b/core/src/main/java/org/teavm/model/PreOptimizingClassHolderSource.java @@ -15,14 +15,14 @@ */ package org.teavm.model; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import org.teavm.optimization.GlobalValueNumbering; import org.teavm.optimization.UnusedVariableElimination; public class PreOptimizingClassHolderSource implements ClassHolderSource { private ClassHolderSource innerClassSource; - private Map cache = new HashMap<>(); + private Map cache = new LinkedHashMap<>(); public PreOptimizingClassHolderSource(ClassHolderSource innerClassSource) { this.innerClassSource = innerClassSource; diff --git a/core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java b/core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java index 2f744d058..e9826dbb8 100644 --- a/core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java +++ b/core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java @@ -22,10 +22,6 @@ import org.teavm.resource.ClasspathResourceReader; import org.teavm.resource.MapperClassHolderSource; import org.teavm.resource.ResourceClassHolderMapper; -/** - * - * @author Alexey Andreev - */ public class ClasspathClassHolderSource implements ClassHolderSource, ClassDateProvider { private MapperClassHolderSource innerClassSource; private ClasspathResourceMapper classPathMapper; diff --git a/core/src/main/java/org/teavm/resource/MapperClassHolderSource.java b/core/src/main/java/org/teavm/resource/MapperClassHolderSource.java index 9ecd50920..ce68d9240 100644 --- a/core/src/main/java/org/teavm/resource/MapperClassHolderSource.java +++ b/core/src/main/java/org/teavm/resource/MapperClassHolderSource.java @@ -20,10 +20,6 @@ import org.teavm.common.Mapper; import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolderSource; -/** - * - * @author Alexey Andreev - */ public class MapperClassHolderSource implements ClassHolderSource { private Mapper mapper; diff --git a/core/src/main/java/org/teavm/wasm/Example.java b/core/src/main/java/org/teavm/wasm/Example.java index 92160d69c..c5708fc0d 100644 --- a/core/src/main/java/org/teavm/wasm/Example.java +++ b/core/src/main/java/org/teavm/wasm/Example.java @@ -15,6 +15,8 @@ */ package org.teavm.wasm; +import org.teavm.wasm.runtime.WasmRuntime; + public final class Example { private Example() { } @@ -27,5 +29,6 @@ public final class Example { a = b; b = c; } + WasmRuntime.print(a); } } diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java index 884ccac28..2a9d8d927 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java @@ -61,29 +61,31 @@ import org.teavm.ast.VariableExpr; import org.teavm.ast.WhileStatement; import org.teavm.wasm.model.WasmFunction; 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.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.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.WasmGetLocal; 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.WasmLocalReference; import org.teavm.wasm.model.expression.WasmReturn; +import org.teavm.wasm.model.expression.WasmSetLocal; import org.teavm.wasm.model.expression.WasmSwitch; class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { + private int firstVariable; private WasmFunction function; private IdentifiedStatement currentContinueTarget; private IdentifiedStatement currentBreakTarget; @@ -92,8 +94,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { private Set usedBlocks = new HashSet<>(); WasmExpression result; - public WasmGenerationVisitor(WasmFunction function) { + public WasmGenerationVisitor(WasmFunction function, int firstVariable) { this.function = function; + this.firstVariable = firstVariable; } @Override @@ -331,11 +334,14 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(AssignmentStatement statement) { Expr left = statement.getLeftValue(); - if (left instanceof VariableExpr) { - VariableExpr varExpr = (VariableExpr) left; - WasmLocal local = function.getLocalVariables().get(varExpr.getIndex()); + if (left == null) { 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 { throw new UnsupportedOperationException("This expression is not supported yet"); } @@ -396,7 +402,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(VariableExpr expr) { - result = new WasmLocalReference(function.getLocalVariables().get(expr.getIndex())); + result = new WasmGetLocal(function.getLocalVariables().get(expr.getIndex() - firstVariable)); } @Override @@ -457,6 +463,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { currentBreakTarget = 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()) { part.acceptVisitor(this); loop.getBody().add(result); 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 cce5e1073..14bbae0ac 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java @@ -19,6 +19,7 @@ import org.teavm.ast.RegularMethodNode; import org.teavm.ast.decompilation.Decompiler; 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; @@ -47,20 +48,21 @@ public class WasmGenerator { inferer.inferTypes(program, 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); VariableType type = inferer.typeOf(varIndex); function.add(new WasmLocal(WasmGeneratorUtil.mapType(type))); } - for (int i = 0; i <= methodReference.parameterCount(); ++i) { - function.getParameters().add(function.getLocalVariables().get(i).getType()); + for (int i = firstVariable; i <= methodReference.parameterCount(); ++i) { + function.getParameters().add(function.getLocalVariables().get(i - firstVariable).getType()); } if (methodReference.getReturnType() != ValueType.VOID) { function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType())); } - WasmGenerationVisitor visitor = new WasmGenerationVisitor(function); + WasmGenerationVisitor visitor = new WasmGenerationVisitor(function, firstVariable); methodAst.getBody().acceptVisitor(visitor); function.getBody().add(visitor.result); diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmMangling.java b/core/src/main/java/org/teavm/wasm/generate/WasmMangling.java index bf65e172e..ecea0d9fb 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmMangling.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmMangling.java @@ -25,7 +25,7 @@ public final class WasmMangling { } 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()); sb.append(mangleType(method.getReturnType())); sb.append(name.length() + "_" + name); @@ -41,8 +41,6 @@ public final class WasmMangling { char c = string.charAt(i); switch (c) { case '$': - case '.': - case '-': sb.append(c); break; case '_': diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmBlock.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmBlock.java index 2439017b7..477b497b1 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmBlock.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmBlock.java @@ -37,4 +37,9 @@ public class WasmBlock extends WasmExpression { public List getBody() { return body; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmBranch.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmBranch.java index cf8240e01..222747e8f 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmBranch.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmBranch.java @@ -54,4 +54,9 @@ public class WasmBranch extends WasmExpression { public void setResult(WasmExpression result) { this.result = result; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmBreak.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmBreak.java index e52993f92..881328814 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmBreak.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmBreak.java @@ -42,4 +42,9 @@ public class WasmBreak extends WasmExpression { public void setResult(WasmExpression result) { this.result = result; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmCall.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmCall.java index ce3213bae..0836ece8e 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmCall.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmCall.java @@ -54,4 +54,9 @@ public class WasmCall extends WasmExpression { public void setImported(boolean imported) { this.imported = imported; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmConditional.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmConditional.java index c53a08785..4a436bdac 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmConditional.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmConditional.java @@ -43,4 +43,9 @@ public class WasmConditional extends WasmExpression { public WasmBlock getElseBlock() { return elseBlock; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmConversion.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmConversion.java index 11728ea45..37afeea24 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmConversion.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmConversion.java @@ -68,4 +68,9 @@ public class WasmConversion extends WasmExpression { Objects.requireNonNull(operand); this.operand = operand; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmDrop.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmDrop.java index 2637e7d94..935acdf93 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmDrop.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmDrop.java @@ -33,4 +33,9 @@ public class WasmDrop extends WasmExpression { Objects.requireNonNull(operand); this.operand = operand; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmExpression.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmExpression.java index b4de610f7..10637b38e 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmExpression.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmExpression.java @@ -18,4 +18,6 @@ package org.teavm.wasm.model.expression; public abstract class WasmExpression { WasmExpression() { } + + public abstract void acceptVisitor(WasmExpressionVisitor visitor); } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmExpressionVisitor.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmExpressionVisitor.java new file mode 100644 index 000000000..10fb97cc3 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmExpressionVisitor.java @@ -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); +} diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloat32Constant.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloat32Constant.java index 0bee8a487..e5d19b923 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloat32Constant.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloat32Constant.java @@ -29,4 +29,9 @@ public class WasmFloat32Constant extends WasmExpression { public void setValue(float value) { this.value = value; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloat64Constant.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloat64Constant.java index 68c9e259c..9601dc00d 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloat64Constant.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloat64Constant.java @@ -29,4 +29,9 @@ public class WasmFloat64Constant extends WasmExpression { public void setValue(double value) { this.value = value; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatBinary.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatBinary.java index 2ae9e9f5f..b389982ff 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatBinary.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatBinary.java @@ -70,4 +70,9 @@ public class WasmFloatBinary extends WasmExpression { Objects.requireNonNull(second); this.second = second; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatBinaryOperation.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatBinaryOperation.java index 957a080e4..ed82a5b3b 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatBinaryOperation.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatBinaryOperation.java @@ -25,5 +25,7 @@ public enum WasmFloatBinaryOperation { LT, LE, GT, - GE + GE, + MIN, + MAX } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatUnary.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatUnary.java index f6f7c34ae..40e2f9e48 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatUnary.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatUnary.java @@ -57,4 +57,9 @@ public class WasmFloatUnary extends WasmExpression { Objects.requireNonNull(operand); this.operand = operand; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatUnaryOperation.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatUnaryOperation.java index 1c848f295..42c455b0c 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatUnaryOperation.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmFloatUnaryOperation.java @@ -23,13 +23,5 @@ public enum WasmFloatUnaryOperation { FLOOR, TRUNC, NEAREST, - MIN, - MAX, - SQRT, - EQ, - NE, - LT, - LE, - GT, - GE + SQRT } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmLocalReference.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmGetLocal.java similarity index 82% rename from core/src/main/java/org/teavm/wasm/model/expression/WasmLocalReference.java rename to core/src/main/java/org/teavm/wasm/model/expression/WasmGetLocal.java index 1fbe730b7..f7bf64e0a 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmLocalReference.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmGetLocal.java @@ -18,10 +18,10 @@ package org.teavm.wasm.model.expression; import java.util.Objects; import org.teavm.wasm.model.WasmLocal; -public class WasmLocalReference extends WasmExpression { +public class WasmGetLocal extends WasmExpression { private WasmLocal local; - public WasmLocalReference(WasmLocal local) { + public WasmGetLocal(WasmLocal local) { Objects.requireNonNull(local); this.local = local; } @@ -34,4 +34,9 @@ public class WasmLocalReference extends WasmExpression { Objects.requireNonNull(local); this.local = local; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmIndirectCall.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmIndirectCall.java index 92661c7f2..5ecb12a1c 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmIndirectCall.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmIndirectCall.java @@ -15,15 +15,19 @@ */ package org.teavm.wasm.model.expression; +import java.util.ArrayList; import java.util.List; import java.util.Objects; public class WasmIndirectCall extends WasmExpression { + private String typeName; private WasmExpression selector; - private List arguments; + private List arguments = new ArrayList<>(); - public WasmIndirectCall(WasmExpression selector) { + public WasmIndirectCall(String typeName, WasmExpression selector) { + Objects.requireNonNull(typeName); Objects.requireNonNull(selector); + this.typeName = typeName; this.selector = selector; } @@ -36,7 +40,21 @@ public class WasmIndirectCall extends WasmExpression { this.selector = selector; } + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + Objects.requireNonNull(typeName); + this.typeName = typeName; + } + public List getArguments() { return arguments; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmInt32Constant.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmInt32Constant.java index 6a5324a53..821053f0f 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmInt32Constant.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmInt32Constant.java @@ -29,4 +29,9 @@ public class WasmInt32Constant extends WasmExpression { public void setValue(int value) { this.value = value; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmInt64Constant.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmInt64Constant.java index 7c7825df1..1b8ee6e46 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmInt64Constant.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmInt64Constant.java @@ -29,4 +29,9 @@ public class WasmInt64Constant extends WasmExpression { public void setValue(long value) { this.value = value; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmIntBinary.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmIntBinary.java index c45772e32..fcdad965d 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmIntBinary.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmIntBinary.java @@ -70,4 +70,9 @@ public class WasmIntBinary extends WasmExpression { Objects.requireNonNull(second); this.second = second; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmIntUnary.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmIntUnary.java index c72631a90..d12a647f5 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmIntUnary.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmIntUnary.java @@ -57,4 +57,9 @@ public class WasmIntUnary extends WasmExpression { Objects.requireNonNull(operand); this.operand = operand; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadFloat32.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadFloat32.java index d3a84aec8..b717be4cd 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadFloat32.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadFloat32.java @@ -43,4 +43,9 @@ public class WasmLoadFloat32 extends WasmExpression { Objects.requireNonNull(index); this.index = index; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadFloat64.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadFloat64.java index dc997bc02..466e65381 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadFloat64.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadFloat64.java @@ -43,4 +43,9 @@ public class WasmLoadFloat64 extends WasmExpression { Objects.requireNonNull(index); this.index = index; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadInt32.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadInt32.java index 009f64c97..ac6e8338f 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadInt32.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadInt32.java @@ -55,4 +55,9 @@ public class WasmLoadInt32 extends WasmExpression { Objects.requireNonNull(convertFrom); this.convertFrom = convertFrom; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadInt64.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadInt64.java index 12110ec66..1933c4a24 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadInt64.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmLoadInt64.java @@ -55,4 +55,9 @@ public class WasmLoadInt64 extends WasmExpression { Objects.requireNonNull(convertFrom); this.convertFrom = convertFrom; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmReturn.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmReturn.java index 6bb92de7b..7242863ec 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmReturn.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmReturn.java @@ -33,4 +33,9 @@ public class WasmReturn extends WasmExpression { public void setValue(WasmExpression value) { this.value = value; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmAssignment.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmSetLocal.java similarity index 84% rename from core/src/main/java/org/teavm/wasm/model/expression/WasmAssignment.java rename to core/src/main/java/org/teavm/wasm/model/expression/WasmSetLocal.java index b102623d6..b295adc65 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmAssignment.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmSetLocal.java @@ -18,11 +18,11 @@ package org.teavm.wasm.model.expression; import java.util.Objects; import org.teavm.wasm.model.WasmLocal; -public class WasmAssignment extends WasmExpression { +public class WasmSetLocal extends WasmExpression { private WasmLocal local; private WasmExpression value; - public WasmAssignment(WasmLocal local, WasmExpression value) { + public WasmSetLocal(WasmLocal local, WasmExpression value) { Objects.requireNonNull(local); Objects.requireNonNull(value); this.local = local; @@ -46,4 +46,9 @@ public class WasmAssignment extends WasmExpression { Objects.requireNonNull(value); this.value = value; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreFloat32.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreFloat32.java index 6f4c44636..f99151ca1 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreFloat32.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreFloat32.java @@ -55,4 +55,9 @@ public class WasmStoreFloat32 extends WasmExpression { Objects.requireNonNull(value); this.value = value; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreFloat64.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreFloat64.java index b35148bd7..867ce13fa 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreFloat64.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreFloat64.java @@ -55,4 +55,9 @@ public class WasmStoreFloat64 extends WasmExpression { Objects.requireNonNull(value); this.value = value; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreInt32.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreInt32.java index add05ea36..bdb5f4331 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreInt32.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreInt32.java @@ -68,4 +68,9 @@ public class WasmStoreInt32 extends WasmExpression { Objects.requireNonNull(convertTo); this.convertTo = convertTo; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreInt64.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreInt64.java index dabf201fd..5e53e43f1 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreInt64.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmStoreInt64.java @@ -68,4 +68,9 @@ public class WasmStoreInt64 extends WasmExpression { Objects.requireNonNull(convertTo); this.convertTo = convertTo; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmSwitch.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmSwitch.java index 9ea88e44e..157c61697 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmSwitch.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmSwitch.java @@ -50,4 +50,9 @@ public class WasmSwitch extends WasmExpression { public List getTargets() { return targets; } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } } diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmUnreachable.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmUnreachable.java index e308c141a..ca760cfef 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmUnreachable.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmUnreachable.java @@ -16,8 +16,11 @@ package org.teavm.wasm.model.expression; 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); } } diff --git a/core/src/main/java/org/teavm/wasm/render/WasmRenderer.java b/core/src/main/java/org/teavm/wasm/render/WasmRenderer.java new file mode 100644 index 000000000..de26e73ae --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/render/WasmRenderer.java @@ -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 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(); + } +} diff --git a/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java b/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java new file mode 100644 index 000000000..d6e5b8d8a --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java @@ -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 usedIdentifiers = new HashSet<>(); + StringBuilder sb = new StringBuilder(); + private Map blockIdentifiers = new HashMap<>(); + private Map 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()); + } +} diff --git a/core/src/main/java/org/teavm/wasm/runtime/WasmRuntime.java b/core/src/main/java/org/teavm/wasm/runtime/WasmRuntime.java index ece9fdee6..5bd382472 100644 --- a/core/src/main/java/org/teavm/wasm/runtime/WasmRuntime.java +++ b/core/src/main/java/org/teavm/wasm/runtime/WasmRuntime.java @@ -42,4 +42,6 @@ public final class WasmRuntime { public static double remainder(double a, double b) { return a - (double) (long) (a / b) * b; } + + public static native void print(int a); }