mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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;
|
||||
|
||||
import org.teavm.wasm.runtime.WasmRuntime;
|
||||
|
||||
public final class Example {
|
||||
private Example() {
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.wasm.runtime;
|
||||
package org.teavm.wasm;
|
||||
|
||||
import org.teavm.interop.Import;
|
||||
|
||||
|
@ -22,19 +22,19 @@ public final class WasmRuntime {
|
|||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
|
@ -45,6 +45,22 @@ public final class WasmRuntime {
|
|||
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")
|
||||
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.WasmGenerator;
|
||||
import org.teavm.wasm.generate.WasmMangling;
|
||||
import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic;
|
||||
import org.teavm.wasm.model.WasmFunction;
|
||||
import org.teavm.wasm.model.WasmModule;
|
||||
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.WasmStoreInt32;
|
||||
import org.teavm.wasm.render.WasmRenderer;
|
||||
import org.teavm.wasm.runtime.WasmRuntime;
|
||||
|
||||
public class WasmTarget implements TeaVMTarget {
|
||||
private TeaVMTargetController controller;
|
||||
|
@ -121,6 +121,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||
new HashSet<>());
|
||||
WasmGenerationContext context = new WasmGenerationContext(classes);
|
||||
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
||||
|
||||
WasmModule module = new WasmModule();
|
||||
|
@ -133,6 +134,9 @@ public class WasmTarget implements TeaVMTarget {
|
|||
&& method.getName().equals("initialize")) {
|
||||
continue;
|
||||
}
|
||||
if (context.getIntrinsic(method.getReference()) != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.hasModifier(ElementModifier.NATIVE)) {
|
||||
if (method.getOwnerName().equals(Structure.class.getName())
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
*/
|
||||
package org.teavm.wasm.generate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.model.AnnotationReader;
|
||||
|
@ -27,15 +29,28 @@ import org.teavm.model.FieldReference;
|
|||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
||||
|
||||
public class WasmGenerationContext {
|
||||
private ClassReaderSource classSource;
|
||||
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
||||
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
||||
private Map<MethodReference, WasmIntrinsic> intrinsicCache = new HashMap<>();
|
||||
|
||||
public WasmGenerationContext(ClassReaderSource 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) {
|
||||
return importedMethods.computeIfAbsent(reference, ref -> {
|
||||
ClassReader cls = classSource.get(ref.getClassName());
|
||||
|
|
|
@ -67,6 +67,8 @@ import org.teavm.model.MethodReference;
|
|||
import org.teavm.model.ValueType;
|
||||
import org.teavm.runtime.Allocator;
|
||||
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.WasmLocal;
|
||||
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.WasmStoreInt64;
|
||||
import org.teavm.wasm.model.expression.WasmSwitch;
|
||||
import org.teavm.wasm.runtime.WasmRuntime;
|
||||
import org.teavm.wasm.WasmRuntime;
|
||||
|
||||
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||
private WasmGenerationContext context;
|
||||
|
@ -416,11 +418,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
@Override
|
||||
public void visit(ConditionalExpr expr) {
|
||||
expr.getCondition().acceptVisitor(this);
|
||||
WasmConditional conditional = new WasmConditional(result);
|
||||
WasmConditional conditional = new WasmConditional(forCondition(result));
|
||||
expr.getConsequent().acceptVisitor(this);
|
||||
conditional.getThenBlock().getBody().add(result);
|
||||
expr.getAlternative().acceptVisitor(this);
|
||||
conditional.getThenBlock().getBody().add(result);
|
||||
conditional.getElseBlock().getBody().add(result);
|
||||
result = conditional;
|
||||
}
|
||||
|
||||
|
@ -456,7 +458,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
@Override
|
||||
public void visit(ConditionalStatement statement) {
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
WasmConditional conditional = new WasmConditional(result);
|
||||
WasmConditional conditional = new WasmConditional(forCondition(result));
|
||||
for (Statement part : statement.getConsequent()) {
|
||||
part.acceptVisitor(this);
|
||||
if (result != null) {
|
||||
|
@ -569,6 +571,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
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) {
|
||||
String methodName = WasmMangling.mangleMethod(expr.getMethod());
|
||||
|
||||
|
@ -900,6 +908,35 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
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) {
|
||||
switch (op) {
|
||||
case EQ:
|
||||
|
@ -945,4 +982,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
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");
|
||||
|
||||
lf();
|
||||
renderBlock(expression.getThenBlock(), "else");
|
||||
renderBlock(expression.getElseBlock(), "else");
|
||||
|
||||
close();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user