mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-10 08:54:11 -08:00
Add WASM generator
This commit is contained in:
parent
888710102f
commit
1484e970dd
|
@ -23,8 +23,6 @@ public enum BinaryOperation {
|
||||||
MODULO,
|
MODULO,
|
||||||
EQUALS,
|
EQUALS,
|
||||||
NOT_EQUALS,
|
NOT_EQUALS,
|
||||||
STRICT_EQUALS,
|
|
||||||
STRICT_NOT_EQUALS,
|
|
||||||
LESS,
|
LESS,
|
||||||
LESS_OR_EQUALS,
|
LESS_OR_EQUALS,
|
||||||
GREATER,
|
GREATER,
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.ast;
|
package org.teavm.ast;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class BreakStatement extends Statement {
|
public class BreakStatement extends Statement {
|
||||||
private IdentifiedStatement target;
|
private IdentifiedStatement target;
|
||||||
private NodeLocation location;
|
private NodeLocation location;
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.ast;
|
package org.teavm.ast;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public abstract class IdentifiedStatement extends Statement {
|
public abstract class IdentifiedStatement extends Statement {
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class InvocationExpr extends Expr {
|
public class InvocationExpr extends Expr {
|
||||||
private MethodReference method;
|
private MethodReference method;
|
||||||
private InvocationType type;
|
private InvocationType type;
|
||||||
|
|
|
@ -20,10 +20,6 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public abstract class MethodNode {
|
public abstract class MethodNode {
|
||||||
private MethodReference reference;
|
private MethodReference reference;
|
||||||
private Set<NodeModifier> modifiers = EnumSet.noneOf(NodeModifier.class);
|
private Set<NodeModifier> modifiers = EnumSet.noneOf(NodeModifier.class);
|
||||||
|
|
|
@ -20,10 +20,6 @@ import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class RegularMethodNode extends MethodNode {
|
public class RegularMethodNode extends MethodNode {
|
||||||
private Statement body;
|
private Statement body;
|
||||||
private List<Integer> variables = new ArrayList<>();
|
private List<Integer> variables = new ArrayList<>();
|
||||||
|
|
|
@ -18,10 +18,6 @@ package org.teavm.ast;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class WhileStatement extends IdentifiedStatement {
|
public class WhileStatement extends IdentifiedStatement {
|
||||||
private Expr condition;
|
private Expr condition;
|
||||||
private List<Statement> body = new ArrayList<>();
|
private List<Statement> body = new ArrayList<>();
|
||||||
|
|
|
@ -270,11 +270,11 @@ class StatementGenerator implements InstructionVisitor {
|
||||||
insn.getConsequent(), insn.getAlternative());
|
insn.getConsequent(), insn.getAlternative());
|
||||||
break;
|
break;
|
||||||
case NOT_NULL:
|
case NOT_NULL:
|
||||||
branch(Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, null, Expr.var(insn.getOperand().getIndex()),
|
branch(Expr.binary(BinaryOperation.NOT_EQUALS, null, Expr.var(insn.getOperand().getIndex()),
|
||||||
Expr.constant(null)), insn.getConsequent(), insn.getAlternative());
|
Expr.constant(null)), insn.getConsequent(), insn.getAlternative());
|
||||||
break;
|
break;
|
||||||
case NULL:
|
case NULL:
|
||||||
branch(Expr.binary(BinaryOperation.STRICT_EQUALS, null, Expr.var(insn.getOperand().getIndex()),
|
branch(Expr.binary(BinaryOperation.EQUALS, null, Expr.var(insn.getOperand().getIndex()),
|
||||||
Expr.constant(null)), insn.getConsequent(), insn.getAlternative());
|
Expr.constant(null)), insn.getConsequent(), insn.getAlternative());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -292,7 +292,7 @@ class StatementGenerator implements InstructionVisitor {
|
||||||
consequent, alternative);
|
consequent, alternative);
|
||||||
break;
|
break;
|
||||||
case REFERENCE_EQUAL:
|
case REFERENCE_EQUAL:
|
||||||
branch(withLocation(Expr.binary(BinaryOperation.STRICT_EQUALS, null, Expr.var(a), Expr.var(b))),
|
branch(withLocation(Expr.binary(BinaryOperation.EQUALS, null, Expr.var(a), Expr.var(b))),
|
||||||
consequent, alternative);
|
consequent, alternative);
|
||||||
break;
|
break;
|
||||||
case NOT_EQUAL:
|
case NOT_EQUAL:
|
||||||
|
@ -300,7 +300,7 @@ class StatementGenerator implements InstructionVisitor {
|
||||||
Expr.var(b))), consequent, alternative);
|
Expr.var(b))), consequent, alternative);
|
||||||
break;
|
break;
|
||||||
case REFERENCE_NOT_EQUAL:
|
case REFERENCE_NOT_EQUAL:
|
||||||
branch(withLocation(Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, null, Expr.var(a), Expr.var(b))),
|
branch(withLocation(Expr.binary(BinaryOperation.NOT_EQUALS, null, Expr.var(a), Expr.var(b))),
|
||||||
consequent, alternative);
|
consequent, alternative);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,6 @@ final class ExprOptimizer {
|
||||||
return Expr.binary(BinaryOperation.LESS_OR_EQUALS, binary.getType(), a, b, expr.getLocation());
|
return Expr.binary(BinaryOperation.LESS_OR_EQUALS, binary.getType(), a, b, expr.getLocation());
|
||||||
case GREATER_OR_EQUALS:
|
case GREATER_OR_EQUALS:
|
||||||
return Expr.binary(BinaryOperation.LESS, binary.getType(), a, b, expr.getLocation());
|
return Expr.binary(BinaryOperation.LESS, binary.getType(), a, b, expr.getLocation());
|
||||||
case STRICT_EQUALS:
|
|
||||||
return Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, binary.getType(), a, b, expr.getLocation());
|
|
||||||
case STRICT_NOT_EQUALS:
|
|
||||||
return Expr.binary(BinaryOperation.STRICT_EQUALS, binary.getType(), a, b, expr.getLocation());
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1391,8 +1391,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
return Precedence.LOGICAL_AND;
|
return Precedence.LOGICAL_AND;
|
||||||
case OR:
|
case OR:
|
||||||
return Precedence.LOGICAL_OR;
|
return Precedence.LOGICAL_OR;
|
||||||
case STRICT_EQUALS:
|
|
||||||
case STRICT_NOT_EQUALS:
|
|
||||||
case EQUALS:
|
case EQUALS:
|
||||||
case NOT_EQUALS:
|
case NOT_EQUALS:
|
||||||
return Precedence.EQUALITY;
|
return Precedence.EQUALITY;
|
||||||
|
@ -1516,10 +1514,10 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
visitBinary(expr, "%", expr.getType() == OperationType.INT);
|
visitBinary(expr, "%", expr.getType() == OperationType.INT);
|
||||||
break;
|
break;
|
||||||
case EQUALS:
|
case EQUALS:
|
||||||
visitBinary(expr, "==", false);
|
visitBinary(expr, "===", false);
|
||||||
break;
|
break;
|
||||||
case NOT_EQUALS:
|
case NOT_EQUALS:
|
||||||
visitBinary(expr, "!=", false);
|
visitBinary(expr, "!==", false);
|
||||||
break;
|
break;
|
||||||
case GREATER:
|
case GREATER:
|
||||||
visitBinary(expr, ">", false);
|
visitBinary(expr, ">", false);
|
||||||
|
@ -1533,12 +1531,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
case LESS_OR_EQUALS:
|
case LESS_OR_EQUALS:
|
||||||
visitBinary(expr, "<=", false);
|
visitBinary(expr, "<=", false);
|
||||||
break;
|
break;
|
||||||
case STRICT_EQUALS:
|
|
||||||
visitBinary(expr, "===", false);
|
|
||||||
break;
|
|
||||||
case STRICT_NOT_EQUALS:
|
|
||||||
visitBinary(expr, "!==", false);
|
|
||||||
break;
|
|
||||||
case COMPARE:
|
case COMPARE:
|
||||||
visitBinaryFunction(expr, naming.getNameForFunction("$rt_compare"));
|
visitBinaryFunction(expr, naming.getNameForFunction("$rt_compare"));
|
||||||
break;
|
break;
|
||||||
|
|
31
core/src/main/java/org/teavm/wasm/Example.java
Normal file
31
core/src/main/java/org/teavm/wasm/Example.java
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public final class Example {
|
||||||
|
private Example() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int a = 0;
|
||||||
|
int b = 1;
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
int c = a + b;
|
||||||
|
a = b;
|
||||||
|
b = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,620 @@
|
||||||
|
/*
|
||||||
|
* 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.generate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.teavm.ast.AssignmentStatement;
|
||||||
|
import org.teavm.ast.BinaryExpr;
|
||||||
|
import org.teavm.ast.BlockStatement;
|
||||||
|
import org.teavm.ast.BreakStatement;
|
||||||
|
import org.teavm.ast.CastExpr;
|
||||||
|
import org.teavm.ast.ConditionalExpr;
|
||||||
|
import org.teavm.ast.ConditionalStatement;
|
||||||
|
import org.teavm.ast.ConstantExpr;
|
||||||
|
import org.teavm.ast.ContinueStatement;
|
||||||
|
import org.teavm.ast.Expr;
|
||||||
|
import org.teavm.ast.ExprVisitor;
|
||||||
|
import org.teavm.ast.GotoPartStatement;
|
||||||
|
import org.teavm.ast.IdentifiedStatement;
|
||||||
|
import org.teavm.ast.InitClassStatement;
|
||||||
|
import org.teavm.ast.InstanceOfExpr;
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.ast.InvocationType;
|
||||||
|
import org.teavm.ast.MonitorEnterStatement;
|
||||||
|
import org.teavm.ast.MonitorExitStatement;
|
||||||
|
import org.teavm.ast.NewArrayExpr;
|
||||||
|
import org.teavm.ast.NewExpr;
|
||||||
|
import org.teavm.ast.NewMultiArrayExpr;
|
||||||
|
import org.teavm.ast.OperationType;
|
||||||
|
import org.teavm.ast.PrimitiveCastExpr;
|
||||||
|
import org.teavm.ast.QualificationExpr;
|
||||||
|
import org.teavm.ast.ReturnStatement;
|
||||||
|
import org.teavm.ast.SequentialStatement;
|
||||||
|
import org.teavm.ast.Statement;
|
||||||
|
import org.teavm.ast.StatementVisitor;
|
||||||
|
import org.teavm.ast.SubscriptExpr;
|
||||||
|
import org.teavm.ast.SwitchClause;
|
||||||
|
import org.teavm.ast.SwitchStatement;
|
||||||
|
import org.teavm.ast.ThrowStatement;
|
||||||
|
import org.teavm.ast.TryCatchStatement;
|
||||||
|
import org.teavm.ast.UnaryExpr;
|
||||||
|
import org.teavm.ast.UnwrapArrayExpr;
|
||||||
|
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.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.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.WasmSwitch;
|
||||||
|
|
||||||
|
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
private WasmFunction function;
|
||||||
|
private IdentifiedStatement currentContinueTarget;
|
||||||
|
private IdentifiedStatement currentBreakTarget;
|
||||||
|
private Map<IdentifiedStatement, WasmBlock> breakTargets = new HashMap<>();
|
||||||
|
private Map<IdentifiedStatement, WasmBlock> continueTargets = new HashMap<>();
|
||||||
|
private Set<WasmBlock> usedBlocks = new HashSet<>();
|
||||||
|
WasmExpression result;
|
||||||
|
|
||||||
|
public WasmGenerationVisitor(WasmFunction function) {
|
||||||
|
this.function = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BinaryExpr expr) {
|
||||||
|
switch (expr.getOperation()) {
|
||||||
|
case ADD:
|
||||||
|
generateBinary(WasmIntBinaryOperation.ADD, WasmFloatBinaryOperation.ADD, expr);
|
||||||
|
break;
|
||||||
|
case SUBTRACT:
|
||||||
|
generateBinary(WasmIntBinaryOperation.SUB, WasmFloatBinaryOperation.ADD, expr);
|
||||||
|
break;
|
||||||
|
case MULTIPLY:
|
||||||
|
generateBinary(WasmIntBinaryOperation.MUL, WasmFloatBinaryOperation.ADD, expr);
|
||||||
|
break;
|
||||||
|
case DIVIDE:
|
||||||
|
generateBinary(WasmIntBinaryOperation.DIV_SIGNED, WasmFloatBinaryOperation.DIV, expr);
|
||||||
|
break;
|
||||||
|
case MODULO: {
|
||||||
|
switch (expr.getType()) {
|
||||||
|
case INT:
|
||||||
|
case LONG:
|
||||||
|
generateBinary(WasmIntBinaryOperation.REM_SIGNED, expr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WasmCall call = new WasmCall("rt$remainder." + typeAsString(expr.getType()), false);
|
||||||
|
expr.getFirstOperand().acceptVisitor(this);
|
||||||
|
call.getArguments().add(result);
|
||||||
|
expr.getSecondOperand().acceptVisitor(this);
|
||||||
|
call.getArguments().add(result);
|
||||||
|
result = call;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BITWISE_AND:
|
||||||
|
generateBinary(WasmIntBinaryOperation.AND, expr);
|
||||||
|
break;
|
||||||
|
case BITWISE_OR:
|
||||||
|
generateBinary(WasmIntBinaryOperation.OR, expr);
|
||||||
|
break;
|
||||||
|
case BITWISE_XOR:
|
||||||
|
generateBinary(WasmIntBinaryOperation.XOR, expr);
|
||||||
|
break;
|
||||||
|
case EQUALS:
|
||||||
|
generateBinary(WasmIntBinaryOperation.EQ, WasmFloatBinaryOperation.EQ, expr);
|
||||||
|
break;
|
||||||
|
case NOT_EQUALS:
|
||||||
|
generateBinary(WasmIntBinaryOperation.NE, WasmFloatBinaryOperation.NE, expr);
|
||||||
|
break;
|
||||||
|
case GREATER:
|
||||||
|
generateBinary(WasmIntBinaryOperation.GT_SIGNED, WasmFloatBinaryOperation.GT, expr);
|
||||||
|
break;
|
||||||
|
case GREATER_OR_EQUALS:
|
||||||
|
generateBinary(WasmIntBinaryOperation.GE_SIGNED, WasmFloatBinaryOperation.GE, expr);
|
||||||
|
break;
|
||||||
|
case LESS:
|
||||||
|
generateBinary(WasmIntBinaryOperation.LT_SIGNED, WasmFloatBinaryOperation.LT, expr);
|
||||||
|
break;
|
||||||
|
case LESS_OR_EQUALS:
|
||||||
|
generateBinary(WasmIntBinaryOperation.LE_SIGNED, WasmFloatBinaryOperation.LE, expr);
|
||||||
|
break;
|
||||||
|
case LEFT_SHIFT:
|
||||||
|
generateBinary(WasmIntBinaryOperation.SHL, expr);
|
||||||
|
break;
|
||||||
|
case RIGHT_SHIFT:
|
||||||
|
generateBinary(WasmIntBinaryOperation.SHR_SIGNED, expr);
|
||||||
|
break;
|
||||||
|
case UNSIGNED_RIGHT_SHIFT:
|
||||||
|
generateBinary(WasmIntBinaryOperation.SHR_UNSIGNED, expr);
|
||||||
|
break;
|
||||||
|
case COMPARE: {
|
||||||
|
WasmCall call = new WasmCall("rt$compare." + typeAsString(expr.getType()), false);
|
||||||
|
expr.getFirstOperand().acceptVisitor(this);
|
||||||
|
call.getArguments().add(result);
|
||||||
|
expr.getSecondOperand().acceptVisitor(this);
|
||||||
|
call.getArguments().add(result);
|
||||||
|
result = call;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AND:
|
||||||
|
generateAnd(expr);
|
||||||
|
break;
|
||||||
|
case OR:
|
||||||
|
generateOr(expr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateBinary(WasmIntBinaryOperation intOp, WasmFloatBinaryOperation floatOp, BinaryExpr expr) {
|
||||||
|
expr.getFirstOperand().acceptVisitor(this);
|
||||||
|
WasmExpression first = result;
|
||||||
|
expr.getSecondOperand().acceptVisitor(this);
|
||||||
|
WasmExpression second = result;
|
||||||
|
|
||||||
|
if (expr.getType() == null) {
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, intOp, first, second);
|
||||||
|
} else {
|
||||||
|
switch (expr.getType()) {
|
||||||
|
case INT:
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, intOp, first, second);
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT64, intOp, first, second);
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
result = new WasmFloatBinary(WasmFloatType.FLOAT32, floatOp, first, second);
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
result = new WasmFloatBinary(WasmFloatType.FLOAT64, floatOp, first, second);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateBinary(WasmIntBinaryOperation intOp, BinaryExpr expr) {
|
||||||
|
expr.getFirstOperand().acceptVisitor(this);
|
||||||
|
WasmExpression first = result;
|
||||||
|
expr.getSecondOperand().acceptVisitor(this);
|
||||||
|
WasmExpression second = result;
|
||||||
|
|
||||||
|
switch (expr.getType()) {
|
||||||
|
case INT:
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, intOp, first, second);
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT64, intOp, first, second);
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
case DOUBLE:
|
||||||
|
throw new AssertionError("Can't translate operation " + intOp + " for type " + expr.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String typeAsString(OperationType type) {
|
||||||
|
switch (type) {
|
||||||
|
case INT:
|
||||||
|
return "i32";
|
||||||
|
case LONG:
|
||||||
|
return "i64";
|
||||||
|
case FLOAT:
|
||||||
|
return "float";
|
||||||
|
case DOUBLE:
|
||||||
|
return "double";
|
||||||
|
}
|
||||||
|
throw new AssertionError(type.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateAnd(BinaryExpr expr) {
|
||||||
|
WasmBlock block = new WasmBlock(false);
|
||||||
|
|
||||||
|
expr.getFirstOperand().acceptVisitor(this);
|
||||||
|
WasmBranch branch = new WasmBranch(negate(result), block);
|
||||||
|
branch.setResult(new WasmInt32Constant(0));
|
||||||
|
block.getBody().add(branch);
|
||||||
|
|
||||||
|
expr.getSecondOperand().acceptVisitor(this);
|
||||||
|
block.getBody().add(result);
|
||||||
|
|
||||||
|
result = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateOr(BinaryExpr expr) {
|
||||||
|
WasmBlock block = new WasmBlock(false);
|
||||||
|
|
||||||
|
expr.getFirstOperand().acceptVisitor(this);
|
||||||
|
WasmBranch branch = new WasmBranch(result, block);
|
||||||
|
branch.setResult(new WasmInt32Constant(1));
|
||||||
|
block.getBody().add(branch);
|
||||||
|
|
||||||
|
expr.getSecondOperand().acceptVisitor(this);
|
||||||
|
block.getBody().add(result);
|
||||||
|
|
||||||
|
result = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(UnaryExpr expr) {
|
||||||
|
switch (expr.getOperation()) {
|
||||||
|
case INT_TO_BYTE:
|
||||||
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
||||||
|
result, new WasmInt32Constant(24));
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHR_SIGNED,
|
||||||
|
result, new WasmInt32Constant(24));
|
||||||
|
break;
|
||||||
|
case INT_TO_SHORT:
|
||||||
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
||||||
|
result, new WasmInt32Constant(16));
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHR_SIGNED,
|
||||||
|
result, new WasmInt32Constant(16));
|
||||||
|
break;
|
||||||
|
case INT_TO_CHAR:
|
||||||
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
||||||
|
result, new WasmInt32Constant(16));
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHR_UNSIGNED,
|
||||||
|
result, new WasmInt32Constant(16));
|
||||||
|
break;
|
||||||
|
case LENGTH:
|
||||||
|
result = new WasmInt32Constant(0);
|
||||||
|
break;
|
||||||
|
case NOT:
|
||||||
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
result = negate(result);
|
||||||
|
break;
|
||||||
|
case NEGATE:
|
||||||
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
switch (expr.getType()) {
|
||||||
|
case INT:
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SUB,
|
||||||
|
new WasmInt32Constant(0), result);
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
result = new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.SUB,
|
||||||
|
new WasmInt64Constant(0), result);
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
result = new WasmFloatBinary(WasmFloatType.FLOAT32, WasmFloatBinaryOperation.SUB,
|
||||||
|
new WasmFloat32Constant(0), result);
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
result = new WasmFloatBinary(WasmFloatType.FLOAT64, WasmFloatBinaryOperation.SUB,
|
||||||
|
new WasmFloat64Constant(0), result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NULL_CHECK:
|
||||||
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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());
|
||||||
|
statement.getRightValue().acceptVisitor(this);
|
||||||
|
result = new WasmAssignment(local, result);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("This expression is not supported yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConditionalExpr expr) {
|
||||||
|
expr.getCondition().acceptVisitor(this);
|
||||||
|
WasmConditional conditional = new WasmConditional(result);
|
||||||
|
expr.getConsequent().acceptVisitor(this);
|
||||||
|
conditional.getThenBlock().getBody().add(result);
|
||||||
|
expr.getAlternative().acceptVisitor(this);
|
||||||
|
conditional.getThenBlock().getBody().add(result);
|
||||||
|
result = conditional;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(SequentialStatement statement) {
|
||||||
|
WasmBlock block = new WasmBlock(false);
|
||||||
|
for (Statement part : statement.getSequence()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
block.getBody().add(result);
|
||||||
|
}
|
||||||
|
result = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConstantExpr expr) {
|
||||||
|
if (expr.getValue() == null) {
|
||||||
|
result = new WasmInt32Constant(0);
|
||||||
|
} else if (expr.getValue() instanceof Integer) {
|
||||||
|
result = new WasmInt32Constant((Integer) expr.getValue());
|
||||||
|
} else if (expr.getValue() instanceof Long) {
|
||||||
|
result = new WasmInt64Constant((Long) expr.getValue());
|
||||||
|
} else if (expr.getValue() instanceof Float) {
|
||||||
|
result = new WasmFloat32Constant((Float) expr.getValue());
|
||||||
|
} else if (expr.getValue() instanceof Double) {
|
||||||
|
result = new WasmFloat64Constant((Double) expr.getValue());
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Constant unsupported: " + expr.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConditionalStatement statement) {
|
||||||
|
statement.getCondition().acceptVisitor(this);
|
||||||
|
WasmConditional conditional = new WasmConditional(result);
|
||||||
|
for (Statement part : statement.getConsequent()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
conditional.getThenBlock().getBody().add(result);
|
||||||
|
}
|
||||||
|
for (Statement part : statement.getAlternative()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
conditional.getElseBlock().getBody().add(result);
|
||||||
|
}
|
||||||
|
result = conditional;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(VariableExpr expr) {
|
||||||
|
result = new WasmLocalReference(function.getLocalVariables().get(expr.getIndex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(SubscriptExpr expr) {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(SwitchStatement statement) {
|
||||||
|
List<WasmBlock> wrappers = new ArrayList<>();
|
||||||
|
|
||||||
|
WasmBlock wrapper = new WasmBlock(false);
|
||||||
|
statement.getValue().acceptVisitor(this);
|
||||||
|
WasmSwitch wasmSwitch = new WasmSwitch(result, wrapper);
|
||||||
|
wrapper.getBody().add(wasmSwitch);
|
||||||
|
|
||||||
|
WasmBlock defaultBlock = new WasmBlock(false);
|
||||||
|
defaultBlock.getBody().add(wrapper);
|
||||||
|
for (Statement part : statement.getDefaultClause()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
defaultBlock.getBody().add(result);
|
||||||
|
}
|
||||||
|
wrapper = defaultBlock;
|
||||||
|
|
||||||
|
for (SwitchClause clause : statement.getClauses()) {
|
||||||
|
WasmBlock caseBlock = new WasmBlock(false);
|
||||||
|
caseBlock.getBody().add(wrapper);
|
||||||
|
wasmSwitch.getTargets().add(wrapper);
|
||||||
|
for (Statement part : clause.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
caseBlock.getBody().add(result);
|
||||||
|
}
|
||||||
|
wrappers.add(caseBlock);
|
||||||
|
wrapper = caseBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (WasmBlock nestedWrapper : wrappers) {
|
||||||
|
nestedWrapper.getBody().add(new WasmBreak(wrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(UnwrapArrayExpr expr) {
|
||||||
|
expr.getArray().acceptVisitor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WhileStatement statement) {
|
||||||
|
WasmBlock wrapper = new WasmBlock(false);
|
||||||
|
WasmBlock loop = new WasmBlock(true);
|
||||||
|
|
||||||
|
continueTargets.put(statement, loop);
|
||||||
|
breakTargets.put(statement, wrapper);
|
||||||
|
IdentifiedStatement oldBreakTarget = currentBreakTarget;
|
||||||
|
IdentifiedStatement oldContinueTarget = currentContinueTarget;
|
||||||
|
currentBreakTarget = statement;
|
||||||
|
currentContinueTarget = statement;
|
||||||
|
|
||||||
|
for (Statement part : statement.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
loop.getBody().add(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBreakTarget = oldBreakTarget;
|
||||||
|
currentContinueTarget = oldContinueTarget;
|
||||||
|
continueTargets.remove(statement);
|
||||||
|
breakTargets.remove(statement);
|
||||||
|
|
||||||
|
if (usedBlocks.contains(wrapper)) {
|
||||||
|
wrapper.getBody().add(loop);
|
||||||
|
result = wrapper;
|
||||||
|
} else {
|
||||||
|
result = loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(InvocationExpr expr) {
|
||||||
|
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) {
|
||||||
|
String methodName = WasmMangling.mangleMethod(expr.getMethod());
|
||||||
|
WasmCall call = new WasmCall(methodName);
|
||||||
|
for (Expr argument : expr.getArguments()) {
|
||||||
|
argument.acceptVisitor(this);
|
||||||
|
call.getArguments().add(result);
|
||||||
|
}
|
||||||
|
result = call;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BlockStatement statement) {
|
||||||
|
WasmBlock block = new WasmBlock(false);
|
||||||
|
|
||||||
|
if (statement.getId() != null) {
|
||||||
|
breakTargets.put(statement, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Statement part : statement.getBody()) {
|
||||||
|
part.acceptVisitor(this);
|
||||||
|
block.getBody().add(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statement.getId() != null) {
|
||||||
|
breakTargets.remove(statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(QualificationExpr expr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BreakStatement statement) {
|
||||||
|
IdentifiedStatement target = statement.getTarget();
|
||||||
|
if (target == null) {
|
||||||
|
target = currentBreakTarget;
|
||||||
|
}
|
||||||
|
WasmBlock wasmTarget = breakTargets.get(target);
|
||||||
|
usedBlocks.add(wasmTarget);
|
||||||
|
result = new WasmBreak(wasmTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NewExpr expr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ContinueStatement statement) {
|
||||||
|
IdentifiedStatement target = statement.getTarget();
|
||||||
|
if (target == null) {
|
||||||
|
target = currentContinueTarget;
|
||||||
|
}
|
||||||
|
WasmBlock wasmTarget = continueTargets.get(target);
|
||||||
|
usedBlocks.add(wasmTarget);
|
||||||
|
result = new WasmBreak(wasmTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NewArrayExpr expr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NewMultiArrayExpr expr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ReturnStatement statement) {
|
||||||
|
if (statement.getResult() != null) {
|
||||||
|
statement.getResult().acceptVisitor(this);
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
result = new WasmReturn(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(InstanceOfExpr expr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ThrowStatement statement) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CastExpr expr) {
|
||||||
|
expr.getValue().acceptVisitor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(InitClassStatement statement) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(PrimitiveCastExpr expr) {
|
||||||
|
expr.getValue().acceptVisitor(this);
|
||||||
|
result = new WasmConversion(WasmGeneratorUtil.mapType(expr.getSource()),
|
||||||
|
WasmGeneratorUtil.mapType(expr.getTarget()), true, result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TryCatchStatement statement) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(GotoPartStatement statement) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(MonitorEnterStatement statement) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(MonitorExitStatement statement) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression negate(WasmExpression expr) {
|
||||||
|
if (expr instanceof WasmIntBinary) {
|
||||||
|
WasmIntBinary binary = (WasmIntBinary) expr;
|
||||||
|
if (binary.getType() == WasmIntType.INT32 && binary.getOperation() == WasmIntBinaryOperation.XOR) {
|
||||||
|
if (isOne(binary.getFirst())) {
|
||||||
|
return binary.getSecond();
|
||||||
|
}
|
||||||
|
if (isOne(binary.getSecond())) {
|
||||||
|
return binary.getFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.XOR, expr, new WasmInt32Constant(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOne(WasmExpression expression) {
|
||||||
|
return expression instanceof WasmInt32Constant && ((WasmInt32Constant) expression).getValue() == 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,5 +15,55 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.wasm.generate;
|
package org.teavm.wasm.generate;
|
||||||
|
|
||||||
|
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.MethodHolder;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.util.TypeInferer;
|
||||||
|
import org.teavm.model.util.VariableType;
|
||||||
|
import org.teavm.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.wasm.model.WasmLocal;
|
||||||
|
|
||||||
public class WasmGenerator {
|
public class WasmGenerator {
|
||||||
|
private Decompiler decompiler;
|
||||||
|
private ClassHolderSource classSource;
|
||||||
|
|
||||||
|
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource) {
|
||||||
|
this.decompiler = decompiler;
|
||||||
|
this.classSource = classSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmFunction generate(MethodReference methodReference) {
|
||||||
|
ClassHolder cls = classSource.get(methodReference.getClassName());
|
||||||
|
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
|
||||||
|
Program program = method.getProgram();
|
||||||
|
|
||||||
|
RegularMethodNode methodAst = decompiler.decompileRegular(method);
|
||||||
|
TypeInferer inferer = new TypeInferer();
|
||||||
|
inferer.inferTypes(program, methodReference);
|
||||||
|
|
||||||
|
WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference));
|
||||||
|
for (int i = 0; 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());
|
||||||
|
}
|
||||||
|
if (methodReference.getReturnType() != ValueType.VOID) {
|
||||||
|
function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
WasmGenerationVisitor visitor = new WasmGenerationVisitor(function);
|
||||||
|
methodAst.getBody().acceptVisitor(visitor);
|
||||||
|
function.getBody().add(visitor.result);
|
||||||
|
|
||||||
|
return function;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* 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.generate;
|
||||||
|
|
||||||
|
import org.teavm.ast.OperationType;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.util.VariableType;
|
||||||
|
import org.teavm.wasm.model.WasmType;
|
||||||
|
|
||||||
|
public final class WasmGeneratorUtil {
|
||||||
|
private WasmGeneratorUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WasmType mapType(OperationType type) {
|
||||||
|
switch (type) {
|
||||||
|
case INT:
|
||||||
|
return WasmType.INT32;
|
||||||
|
case LONG:
|
||||||
|
return WasmType.INT64;
|
||||||
|
case FLOAT:
|
||||||
|
return WasmType.FLOAT32;
|
||||||
|
case DOUBLE:
|
||||||
|
return WasmType.FLOAT64;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(type.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WasmType mapType(ValueType type) {
|
||||||
|
if (type instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) type).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
case BYTE:
|
||||||
|
case SHORT:
|
||||||
|
case CHARACTER:
|
||||||
|
case INTEGER:
|
||||||
|
return WasmType.INT32;
|
||||||
|
case LONG:
|
||||||
|
return WasmType.INT64;
|
||||||
|
case FLOAT:
|
||||||
|
return WasmType.FLOAT32;
|
||||||
|
case DOUBLE:
|
||||||
|
return WasmType.FLOAT64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WasmType.INT32;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WasmType mapType(VariableType type) {
|
||||||
|
switch (type) {
|
||||||
|
case INT:
|
||||||
|
return WasmType.INT32;
|
||||||
|
case LONG:
|
||||||
|
return WasmType.INT64;
|
||||||
|
case FLOAT:
|
||||||
|
return WasmType.FLOAT32;
|
||||||
|
case DOUBLE:
|
||||||
|
return WasmType.FLOAT64;
|
||||||
|
default:
|
||||||
|
return WasmType.INT32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
core/src/main/java/org/teavm/wasm/generate/WasmMangling.java
Normal file
97
core/src/main/java/org/teavm/wasm/generate/WasmMangling.java
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* 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.generate;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
public final class WasmMangling {
|
||||||
|
private WasmMangling() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mangleMethod(MethodReference method) {
|
||||||
|
StringBuilder sb = new StringBuilder("method$" + mangleString(method.getClassName()) + "$");
|
||||||
|
String name = mangleString(method.getName());
|
||||||
|
sb.append(mangleType(method.getReturnType()));
|
||||||
|
sb.append(name.length() + "_" + name);
|
||||||
|
sb.append(Arrays.stream(method.getParameterTypes())
|
||||||
|
.map(WasmMangling::mangleType)
|
||||||
|
.collect(Collectors.joining()));
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String mangleString(String string) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < string.length(); ++i) {
|
||||||
|
char c = string.charAt(i);
|
||||||
|
switch (c) {
|
||||||
|
case '$':
|
||||||
|
case '.':
|
||||||
|
case '-':
|
||||||
|
sb.append(c);
|
||||||
|
break;
|
||||||
|
case '_':
|
||||||
|
sb.append("__");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9') {
|
||||||
|
sb.append(c);
|
||||||
|
} else {
|
||||||
|
sb.append('_')
|
||||||
|
.append(Character.forDigit(c >>> 12, 16))
|
||||||
|
.append(Character.forDigit((c >>> 8) & 0xF, 16))
|
||||||
|
.append(Character.forDigit((c >>> 4) & 0xF, 16))
|
||||||
|
.append(Character.forDigit(c & 0xF, 16));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mangleType(ValueType type) {
|
||||||
|
if (type instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) type).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
return "Z";
|
||||||
|
case BYTE:
|
||||||
|
return "B";
|
||||||
|
case SHORT:
|
||||||
|
return "S";
|
||||||
|
case CHARACTER:
|
||||||
|
return "C";
|
||||||
|
case INTEGER:
|
||||||
|
return "I";
|
||||||
|
case LONG:
|
||||||
|
return "L";
|
||||||
|
case FLOAT:
|
||||||
|
return "F";
|
||||||
|
case DOUBLE:
|
||||||
|
return "D";
|
||||||
|
}
|
||||||
|
} else if (type instanceof ValueType.Void) {
|
||||||
|
return "V";
|
||||||
|
} else if (type instanceof ValueType.Array) {
|
||||||
|
return "A" + mangleType(((ValueType.Array) type).getItemType());
|
||||||
|
} else if (type instanceof ValueType.Object) {
|
||||||
|
String className = ((ValueType.Object) type).getClassName();
|
||||||
|
return "L" + className.length() + "_" + className;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Don't know how to mangle " + type);
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,8 +20,11 @@ import java.util.Objects;
|
||||||
public class WasmBranch extends WasmExpression {
|
public class WasmBranch extends WasmExpression {
|
||||||
private WasmExpression condition;
|
private WasmExpression condition;
|
||||||
private WasmBlock target;
|
private WasmBlock target;
|
||||||
|
private WasmExpression result;
|
||||||
|
|
||||||
public WasmBranch(WasmExpression condition, WasmBlock target) {
|
public WasmBranch(WasmExpression condition, WasmBlock target) {
|
||||||
|
Objects.requireNonNull(condition);
|
||||||
|
Objects.requireNonNull(target);
|
||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
@ -43,4 +46,12 @@ public class WasmBranch extends WasmExpression {
|
||||||
Objects.requireNonNull(target);
|
Objects.requireNonNull(target);
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WasmExpression getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResult(WasmExpression result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class WasmBreak extends WasmExpression {
|
||||||
|
private WasmBlock target;
|
||||||
|
private WasmExpression result;
|
||||||
|
|
||||||
|
public WasmBreak(WasmBlock target) {
|
||||||
|
Objects.requireNonNull(target);
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmBlock getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(WasmBlock target) {
|
||||||
|
Objects.requireNonNull(target);
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmExpression getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResult(WasmExpression result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
}
|
45
core/src/main/java/org/teavm/wasm/runtime/WasmRuntime.java
Normal file
45
core/src/main/java/org/teavm/wasm/runtime/WasmRuntime.java
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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.runtime;
|
||||||
|
|
||||||
|
public final class WasmRuntime {
|
||||||
|
private WasmRuntime() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(int a, int b) {
|
||||||
|
return a > b ? 1 : a < b ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(long a, long b) {
|
||||||
|
return a > b ? 1 : a < b ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(float a, float b) {
|
||||||
|
return a > b ? 1 : a < b ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(double a, double b) {
|
||||||
|
return a > b ? 1 : a < b ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float remainder(float a, float b) {
|
||||||
|
return a - (float) (int) (a / b) * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double remainder(double a, double b) {
|
||||||
|
return a - (double) (long) (a / b) * b;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user