mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-18 04:14:50 -08:00
Fix minor bugs in WASM backend
This commit is contained in:
parent
a1fe87ff70
commit
45993091e4
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.wasm;
|
package org.teavm.wasm;
|
||||||
|
|
||||||
import org.teavm.wasm.runtime.WasmRuntime;
|
|
||||||
|
|
||||||
public final class Example {
|
public final class Example {
|
||||||
private Example() {
|
private Example() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.teavm.wasm.runtime;
|
package org.teavm.wasm;
|
||||||
|
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
|
|
||||||
|
@ -22,19 +22,19 @@ public final class WasmRuntime {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int compare(int a, int b) {
|
public static int compare(int a, int b) {
|
||||||
return a > b ? 1 : a < b ? -1 : 0;
|
return gt(a, b) ? 1 : lt(a, b) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int compare(long a, long b) {
|
public static int compare(long a, long b) {
|
||||||
return a > b ? 1 : a < b ? -1 : 0;
|
return gt(a, b) ? 1 : lt(a, b) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int compare(float a, float b) {
|
public static int compare(float a, float b) {
|
||||||
return a > b ? 1 : a < b ? -1 : 0;
|
return gt(a, b) ? 1 : lt(a, b) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int compare(double a, double b) {
|
public static int compare(double a, double b) {
|
||||||
return a > b ? 1 : a < b ? -1 : 0;
|
return gt(a, b) ? 1 : lt(a, b) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float remainder(float a, float b) {
|
public static float remainder(float a, float b) {
|
||||||
|
@ -45,6 +45,22 @@ public final class WasmRuntime {
|
||||||
return a - (double) (long) (a / b) * b;
|
return a - (double) (long) (a / b) * b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static native boolean lt(int a, int b);
|
||||||
|
|
||||||
|
private static native boolean gt(int a, int b);
|
||||||
|
|
||||||
|
private static native boolean lt(long a, long b);
|
||||||
|
|
||||||
|
private static native boolean gt(long a, long b);
|
||||||
|
|
||||||
|
private static native boolean lt(float a, float b);
|
||||||
|
|
||||||
|
private static native boolean gt(float a, float b);
|
||||||
|
|
||||||
|
private static native boolean lt(double a, double b);
|
||||||
|
|
||||||
|
private static native boolean gt(double a, double b);
|
||||||
|
|
||||||
@Import(name = "print", module = "spectest")
|
@Import(name = "print", module = "spectest")
|
||||||
public static native void print(int a);
|
public static native void print(int a);
|
||||||
}
|
}
|
|
@ -53,6 +53,7 @@ import org.teavm.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.wasm.generate.WasmGenerationContext;
|
import org.teavm.wasm.generate.WasmGenerationContext;
|
||||||
import org.teavm.wasm.generate.WasmGenerator;
|
import org.teavm.wasm.generate.WasmGenerator;
|
||||||
import org.teavm.wasm.generate.WasmMangling;
|
import org.teavm.wasm.generate.WasmMangling;
|
||||||
|
import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic;
|
||||||
import org.teavm.wasm.model.WasmFunction;
|
import org.teavm.wasm.model.WasmFunction;
|
||||||
import org.teavm.wasm.model.WasmModule;
|
import org.teavm.wasm.model.WasmModule;
|
||||||
import org.teavm.wasm.model.WasmType;
|
import org.teavm.wasm.model.WasmType;
|
||||||
|
@ -69,7 +70,6 @@ import org.teavm.wasm.model.expression.WasmLoadInt32;
|
||||||
import org.teavm.wasm.model.expression.WasmReturn;
|
import org.teavm.wasm.model.expression.WasmReturn;
|
||||||
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
||||||
import org.teavm.wasm.render.WasmRenderer;
|
import org.teavm.wasm.render.WasmRenderer;
|
||||||
import org.teavm.wasm.runtime.WasmRuntime;
|
|
||||||
|
|
||||||
public class WasmTarget implements TeaVMTarget {
|
public class WasmTarget implements TeaVMTarget {
|
||||||
private TeaVMTargetController controller;
|
private TeaVMTargetController controller;
|
||||||
|
@ -121,6 +121,7 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||||
new HashSet<>());
|
new HashSet<>());
|
||||||
WasmGenerationContext context = new WasmGenerationContext(classes);
|
WasmGenerationContext context = new WasmGenerationContext(classes);
|
||||||
|
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
||||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
||||||
|
|
||||||
WasmModule module = new WasmModule();
|
WasmModule module = new WasmModule();
|
||||||
|
@ -133,6 +134,9 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
&& method.getName().equals("initialize")) {
|
&& method.getName().equals("initialize")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (context.getIntrinsic(method.getReference()) != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (method.hasModifier(ElementModifier.NATIVE)) {
|
if (method.hasModifier(ElementModifier.NATIVE)) {
|
||||||
if (method.getOwnerName().equals(Structure.class.getName())
|
if (method.getOwnerName().equals(Structure.class.getName())
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.wasm.generate;
|
package org.teavm.wasm.generate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
import org.teavm.model.AnnotationReader;
|
import org.teavm.model.AnnotationReader;
|
||||||
|
@ -27,15 +29,28 @@ import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
||||||
|
|
||||||
public class WasmGenerationContext {
|
public class WasmGenerationContext {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
||||||
|
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
||||||
|
private Map<MethodReference, WasmIntrinsic> intrinsicCache = new HashMap<>();
|
||||||
|
|
||||||
public WasmGenerationContext(ClassReaderSource classSource) {
|
public WasmGenerationContext(ClassReaderSource classSource) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addIntrinsic(WasmIntrinsic intrinsic) {
|
||||||
|
intrinsics.add(intrinsic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WasmIntrinsic getIntrinsic(MethodReference method) {
|
||||||
|
return intrinsicCache.computeIfAbsent(method, key -> intrinsics.stream()
|
||||||
|
.filter(intrinsic -> intrinsic.isApplicable(key))
|
||||||
|
.findFirst().orElse(null));
|
||||||
|
}
|
||||||
|
|
||||||
public ImportedMethod getImportedMethod(MethodReference reference) {
|
public ImportedMethod getImportedMethod(MethodReference reference) {
|
||||||
return importedMethods.computeIfAbsent(reference, ref -> {
|
return importedMethods.computeIfAbsent(reference, ref -> {
|
||||||
ClassReader cls = classSource.get(ref.getClassName());
|
ClassReader cls = classSource.get(ref.getClassName());
|
||||||
|
|
|
@ -67,6 +67,8 @@ import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.runtime.Allocator;
|
import org.teavm.runtime.Allocator;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
|
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
||||||
|
import org.teavm.wasm.intrinsics.WasmIntrinsicManager;
|
||||||
import org.teavm.wasm.model.WasmFunction;
|
import org.teavm.wasm.model.WasmFunction;
|
||||||
import org.teavm.wasm.model.WasmLocal;
|
import org.teavm.wasm.model.WasmLocal;
|
||||||
import org.teavm.wasm.model.WasmType;
|
import org.teavm.wasm.model.WasmType;
|
||||||
|
@ -102,7 +104,7 @@ import org.teavm.wasm.model.expression.WasmStoreFloat64;
|
||||||
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
||||||
import org.teavm.wasm.model.expression.WasmStoreInt64;
|
import org.teavm.wasm.model.expression.WasmStoreInt64;
|
||||||
import org.teavm.wasm.model.expression.WasmSwitch;
|
import org.teavm.wasm.model.expression.WasmSwitch;
|
||||||
import org.teavm.wasm.runtime.WasmRuntime;
|
import org.teavm.wasm.WasmRuntime;
|
||||||
|
|
||||||
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
private WasmGenerationContext context;
|
private WasmGenerationContext context;
|
||||||
|
@ -416,11 +418,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConditionalExpr expr) {
|
public void visit(ConditionalExpr expr) {
|
||||||
expr.getCondition().acceptVisitor(this);
|
expr.getCondition().acceptVisitor(this);
|
||||||
WasmConditional conditional = new WasmConditional(result);
|
WasmConditional conditional = new WasmConditional(forCondition(result));
|
||||||
expr.getConsequent().acceptVisitor(this);
|
expr.getConsequent().acceptVisitor(this);
|
||||||
conditional.getThenBlock().getBody().add(result);
|
conditional.getThenBlock().getBody().add(result);
|
||||||
expr.getAlternative().acceptVisitor(this);
|
expr.getAlternative().acceptVisitor(this);
|
||||||
conditional.getThenBlock().getBody().add(result);
|
conditional.getElseBlock().getBody().add(result);
|
||||||
result = conditional;
|
result = conditional;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,7 +458,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConditionalStatement statement) {
|
public void visit(ConditionalStatement statement) {
|
||||||
statement.getCondition().acceptVisitor(this);
|
statement.getCondition().acceptVisitor(this);
|
||||||
WasmConditional conditional = new WasmConditional(result);
|
WasmConditional conditional = new WasmConditional(forCondition(result));
|
||||||
for (Statement part : statement.getConsequent()) {
|
for (Statement part : statement.getConsequent()) {
|
||||||
part.acceptVisitor(this);
|
part.acceptVisitor(this);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
@ -569,6 +571,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WasmIntrinsic intrinsic = context.getIntrinsic(expr.getMethod());
|
||||||
|
if (intrinsic != null) {
|
||||||
|
result = intrinsic.apply(expr, intrinsicManager);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) {
|
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) {
|
||||||
String methodName = WasmMangling.mangleMethod(expr.getMethod());
|
String methodName = WasmMangling.mangleMethod(expr.getMethod());
|
||||||
|
|
||||||
|
@ -900,6 +908,35 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
return expression instanceof WasmInt32Constant && ((WasmInt32Constant) expression).getValue() == 1;
|
return expression instanceof WasmInt32Constant && ((WasmInt32Constant) expression).getValue() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isZero(WasmExpression expression) {
|
||||||
|
return expression instanceof WasmInt32Constant && ((WasmInt32Constant) expression).getValue() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression forCondition(WasmExpression expression) {
|
||||||
|
if (expression instanceof WasmIntBinary) {
|
||||||
|
WasmIntBinary binary = (WasmIntBinary) expression;
|
||||||
|
switch (binary.getOperation()) {
|
||||||
|
case EQ:
|
||||||
|
if (isZero(binary.getFirst())) {
|
||||||
|
return negate(binary.getSecond());
|
||||||
|
} else if (isZero(binary.getSecond())) {
|
||||||
|
return negate(binary.getFirst());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NE:
|
||||||
|
if (isZero(binary.getFirst())) {
|
||||||
|
return binary.getSecond();
|
||||||
|
} else if (isZero(binary.getSecond())) {
|
||||||
|
return binary.getFirst();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
private WasmIntBinaryOperation negate(WasmIntBinaryOperation op) {
|
private WasmIntBinaryOperation negate(WasmIntBinaryOperation op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case EQ:
|
case EQ:
|
||||||
|
@ -945,4 +982,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmIntrinsicManager intrinsicManager = new WasmIntrinsicManager() {
|
||||||
|
@Override
|
||||||
|
public WasmExpression generate(Expr expr) {
|
||||||
|
expr.acceptVisitor(WasmGenerationVisitor.this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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.intrinsics;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.wasm.model.expression.WasmExpression;
|
||||||
|
|
||||||
|
public interface WasmIntrinsic {
|
||||||
|
boolean isApplicable(MethodReference methodReference);
|
||||||
|
|
||||||
|
WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager);
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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.intrinsics;
|
||||||
|
|
||||||
|
import org.teavm.ast.Expr;
|
||||||
|
import org.teavm.wasm.model.expression.WasmExpression;
|
||||||
|
|
||||||
|
public interface WasmIntrinsicManager {
|
||||||
|
WasmExpression generate(Expr expr);
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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.intrinsics;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.wasm.WasmRuntime;
|
||||||
|
import org.teavm.wasm.generate.WasmGeneratorUtil;
|
||||||
|
import org.teavm.wasm.model.WasmType;
|
||||||
|
import org.teavm.wasm.model.expression.WasmExpression;
|
||||||
|
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.WasmIntBinary;
|
||||||
|
import org.teavm.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
|
import org.teavm.wasm.model.expression.WasmIntType;
|
||||||
|
|
||||||
|
public class WasmRuntimeIntrinsic implements WasmIntrinsic {
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(MethodReference methodReference) {
|
||||||
|
return methodReference.getClassName().equals(WasmRuntime.class.getName()) &&
|
||||||
|
(methodReference.getName().equals("lt") || methodReference.getName().equals("gt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||||
|
WasmType type = WasmGeneratorUtil.mapType(invocation.getMethod().parameterType(0));
|
||||||
|
|
||||||
|
WasmExpression first = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression second = manager.generate(invocation.getArguments().get(1));
|
||||||
|
|
||||||
|
WasmIntBinaryOperation intOp;
|
||||||
|
WasmFloatBinaryOperation floatOp;
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "lt":
|
||||||
|
intOp = WasmIntBinaryOperation.LT_SIGNED;
|
||||||
|
floatOp = WasmFloatBinaryOperation.LT;
|
||||||
|
break;
|
||||||
|
case "gt":
|
||||||
|
intOp = WasmIntBinaryOperation.GT_SIGNED;
|
||||||
|
floatOp = WasmFloatBinaryOperation.GT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(invocation.getMethod().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case INT32:
|
||||||
|
return new WasmIntBinary(WasmIntType.INT32, intOp, first, second);
|
||||||
|
case INT64:
|
||||||
|
return new WasmIntBinary(WasmIntType.INT64, intOp, first, second);
|
||||||
|
case FLOAT32:
|
||||||
|
return new WasmFloatBinary(WasmFloatType.FLOAT32, floatOp, first, second);
|
||||||
|
case FLOAT64:
|
||||||
|
return new WasmFloatBinary(WasmFloatType.FLOAT64, floatOp, first, second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -180,7 +180,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
renderBlock(expression.getThenBlock(), "then");
|
renderBlock(expression.getThenBlock(), "then");
|
||||||
|
|
||||||
lf();
|
lf();
|
||||||
renderBlock(expression.getThenBlock(), "else");
|
renderBlock(expression.getElseBlock(), "else");
|
||||||
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user