mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Add WASM generator
This commit is contained in:
parent
888710102f
commit
1484e970dd
|
@ -23,8 +23,6 @@ public enum BinaryOperation {
|
|||
MODULO,
|
||||
EQUALS,
|
||||
NOT_EQUALS,
|
||||
STRICT_EQUALS,
|
||||
STRICT_NOT_EQUALS,
|
||||
LESS,
|
||||
LESS_OR_EQUALS,
|
||||
GREATER,
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
*/
|
||||
package org.teavm.ast;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class BreakStatement extends Statement {
|
||||
private IdentifiedStatement target;
|
||||
private NodeLocation location;
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
*/
|
||||
package org.teavm.ast;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public abstract class IdentifiedStatement extends Statement {
|
||||
private String id;
|
||||
|
||||
|
|
|
@ -20,10 +20,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class InvocationExpr extends Expr {
|
||||
private MethodReference method;
|
||||
private InvocationType type;
|
||||
|
|
|
@ -20,10 +20,6 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public abstract class MethodNode {
|
||||
private MethodReference reference;
|
||||
private Set<NodeModifier> modifiers = EnumSet.noneOf(NodeModifier.class);
|
||||
|
|
|
@ -20,10 +20,6 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class RegularMethodNode extends MethodNode {
|
||||
private Statement body;
|
||||
private List<Integer> variables = new ArrayList<>();
|
||||
|
|
|
@ -18,10 +18,6 @@ package org.teavm.ast;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class WhileStatement extends IdentifiedStatement {
|
||||
private Expr condition;
|
||||
private List<Statement> body = new ArrayList<>();
|
||||
|
|
|
@ -270,11 +270,11 @@ class StatementGenerator implements InstructionVisitor {
|
|||
insn.getConsequent(), insn.getAlternative());
|
||||
break;
|
||||
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());
|
||||
break;
|
||||
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());
|
||||
break;
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ class StatementGenerator implements InstructionVisitor {
|
|||
consequent, alternative);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
|
@ -300,7 +300,7 @@ class StatementGenerator implements InstructionVisitor {
|
|||
Expr.var(b))), consequent, alternative);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -48,10 +48,6 @@ final class ExprOptimizer {
|
|||
return Expr.binary(BinaryOperation.LESS_OR_EQUALS, binary.getType(), a, b, expr.getLocation());
|
||||
case GREATER_OR_EQUALS:
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1391,8 +1391,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
return Precedence.LOGICAL_AND;
|
||||
case OR:
|
||||
return Precedence.LOGICAL_OR;
|
||||
case STRICT_EQUALS:
|
||||
case STRICT_NOT_EQUALS:
|
||||
case EQUALS:
|
||||
case NOT_EQUALS:
|
||||
return Precedence.EQUALITY;
|
||||
|
@ -1516,10 +1514,10 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
visitBinary(expr, "%", expr.getType() == OperationType.INT);
|
||||
break;
|
||||
case EQUALS:
|
||||
visitBinary(expr, "==", false);
|
||||
visitBinary(expr, "===", false);
|
||||
break;
|
||||
case NOT_EQUALS:
|
||||
visitBinary(expr, "!=", false);
|
||||
visitBinary(expr, "!==", false);
|
||||
break;
|
||||
case GREATER:
|
||||
visitBinary(expr, ">", false);
|
||||
|
@ -1533,12 +1531,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
case LESS_OR_EQUALS:
|
||||
visitBinary(expr, "<=", false);
|
||||
break;
|
||||
case STRICT_EQUALS:
|
||||
visitBinary(expr, "===", false);
|
||||
break;
|
||||
case STRICT_NOT_EQUALS:
|
||||
visitBinary(expr, "!==", false);
|
||||
break;
|
||||
case COMPARE:
|
||||
visitBinaryFunction(expr, naming.getNameForFunction("$rt_compare"));
|
||||
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;
|
||||
|
||||
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 {
|
||||
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 {
|
||||
private WasmExpression condition;
|
||||
private WasmBlock target;
|
||||
private WasmExpression result;
|
||||
|
||||
public WasmBranch(WasmExpression condition, WasmBlock target) {
|
||||
Objects.requireNonNull(condition);
|
||||
Objects.requireNonNull(target);
|
||||
this.condition = condition;
|
||||
this.target = target;
|
||||
}
|
||||
|
@ -43,4 +46,12 @@ public class WasmBranch extends WasmExpression {
|
|||
Objects.requireNonNull(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