Fix minor bugs in WASM backend

This commit is contained in:
Alexey Andreev 2016-08-09 17:14:30 +03:00
parent a1fe87ff70
commit 45993091e4
9 changed files with 213 additions and 13 deletions

View File

@ -15,8 +15,6 @@
*/
package org.teavm.wasm;
import org.teavm.wasm.runtime.WasmRuntime;
public final class Example {
private Example() {
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -180,7 +180,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
renderBlock(expression.getThenBlock(), "then");
lf();
renderBlock(expression.getThenBlock(), "else");
renderBlock(expression.getElseBlock(), "else");
close();
}