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.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<String, Item> cache = new HashMap<>();
private Map<String, Item> cache = new LinkedHashMap<>();
private Set<String> newClasses = new HashSet<>();
private ProgramIO programIO;

View File

@ -17,16 +17,9 @@ package org.teavm.common;
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> {
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 static class Wrapper<S> {

View File

@ -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<String, ClassHolder> generatedClasses = new HashMap<>();
private Map<String, ClassHolder> generatedClasses = new LinkedHashMap<>();
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) {
this.innerSource = innerSource;

View File

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

View File

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

View File

@ -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<String, ClassHolder> classes = new ConcurrentHashMap<>();
private Map<String, ClassHolder> classes = new LinkedHashMap<>();
@Override
public Set<String> getClassNames() {

View File

@ -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<String, ClassHolder> cache = new HashMap<>();
private Map<String, ClassHolder> cache = new LinkedHashMap<>();
public PreOptimizingClassHolderSource(ClassHolderSource innerClassSource) {
this.innerClassSource = innerClassSource;

View File

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

View File

@ -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<String, ClassHolder> mapper;

View File

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

View File

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

View File

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

View File

@ -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 '_':

View File

@ -37,4 +37,9 @@ public class WasmBlock extends WasmExpression {
public List<WasmExpression> getBody() {
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) {
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) {
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) {
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() {
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);
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);
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 {
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) {
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) {
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);
this.second = second;
}
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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<WasmExpression> arguments;
private List<WasmExpression> 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<WasmExpression> getArguments() {
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) {
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) {
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);
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);
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);
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);
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);
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);
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) {
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 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);
}
}

View File

@ -55,4 +55,9 @@ public class WasmStoreFloat32 extends WasmExpression {
Objects.requireNonNull(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);
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);
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);
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() {
return targets;
}
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
}

View File

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

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) {
return a - (double) (long) (a / b) * b;
}
public static native void print(int a);
}