mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: fix issie with type inference for array set, implement some intrinsics
This commit is contained in:
parent
1ba1dcfc09
commit
f19c211b2a
|
@ -263,9 +263,11 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression storeArrayItem(WasmExpression array, WasmExpression index, WasmExpression value,
|
protected WasmExpression storeArrayItem(WasmExpression array, WasmExpression index, Expr value,
|
||||||
ArrayType type) {
|
ArrayType type) {
|
||||||
return storeArrayItem(getArrayElementPointer(array, index, type), value, type);
|
accept(value);
|
||||||
|
var wasmValue = result;
|
||||||
|
return storeArrayItem(getArrayElementPointer(array, index, type), wasmValue, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WasmExpression storeArrayItem(WasmExpression array, WasmExpression value, ArrayType type) {
|
private static WasmExpression storeArrayItem(WasmExpression array, WasmExpression value, ArrayType type) {
|
||||||
|
|
|
@ -513,12 +513,10 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
var array = result;
|
var array = result;
|
||||||
leftValue.getIndex().acceptVisitor(this);
|
leftValue.getIndex().acceptVisitor(this);
|
||||||
var index = result;
|
var index = result;
|
||||||
rightValue.acceptVisitor(this);
|
resultConsumer.add(storeArrayItem(array, index, rightValue, leftValue.getType()));
|
||||||
var value = result;
|
|
||||||
resultConsumer.add(storeArrayItem(array, index, value, leftValue.getType()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract WasmExpression storeArrayItem(WasmExpression array, WasmExpression index, WasmExpression value,
|
protected abstract WasmExpression storeArrayItem(WasmExpression array, WasmExpression index, Expr value,
|
||||||
ArrayType type);
|
ArrayType type);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1081,9 +1079,9 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||||
block.getBody());
|
block.getBody());
|
||||||
|
|
||||||
for (int i = 0; i < expr.getData().size(); ++i) {
|
for (int i = 0; i < expr.getData().size(); ++i) {
|
||||||
expr.getData().get(i).acceptVisitor(this);
|
|
||||||
var arrayData = unwrapArray(new WasmGetLocal(array));
|
var arrayData = unwrapArray(new WasmGetLocal(array));
|
||||||
block.getBody().add(storeArrayItem(arrayData, new WasmInt32Constant(i), result, arrayType));
|
block.getBody().add(storeArrayItem(arrayData, new WasmInt32Constant(i), expr.getData().get(i),
|
||||||
|
arrayType));
|
||||||
}
|
}
|
||||||
|
|
||||||
block.getBody().add(new WasmGetLocal(array));
|
block.getBody().add(new WasmGetLocal(array));
|
||||||
|
|
|
@ -562,7 +562,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
|
|
||||||
private WasmFunction generateArrayGetPrimitiveFunction(PrimitiveType type) {
|
private WasmFunction generateArrayGetPrimitiveFunction(PrimitiveType type) {
|
||||||
var function = new WasmFunction(getArrayGetType());
|
var function = new WasmFunction(getArrayGetType());
|
||||||
arrayGetObjectFunction.setName(names.topLevel("Array<" + names.suggestForType(ValueType.primitive(type))
|
function.setName(names.topLevel("Array<" + names.suggestForType(ValueType.primitive(type))
|
||||||
+ ">::get"));
|
+ ">::get"));
|
||||||
module.functions.add(function);
|
module.functions.add(function);
|
||||||
function.setReferenced(true);
|
function.setReferenced(true);
|
||||||
|
|
|
@ -151,12 +151,14 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmExpression storeArrayItem(WasmExpression array, WasmExpression index, WasmExpression value,
|
protected WasmExpression storeArrayItem(WasmExpression array, WasmExpression index, Expr value,
|
||||||
ArrayType type) {
|
ArrayType type) {
|
||||||
array.acceptVisitor(typeInference);
|
array.acceptVisitor(typeInference);
|
||||||
var arrayRefType = (WasmType.CompositeReference) typeInference.getResult();
|
var arrayRefType = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
var arrayType = (WasmArray) arrayRefType.composite;
|
var arrayType = (WasmArray) arrayRefType.composite;
|
||||||
return new WasmArraySet(arrayType, array, index, value);
|
accept(value, arrayType.getElementType().asUnpackedType());
|
||||||
|
var wasmValue = result;
|
||||||
|
return new WasmArraySet(arrayType, array, index, wasmValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.backend.wasm.intrinsics.gc;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmFloat64Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmFloatBinary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt64Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
|
|
||||||
|
public class DoubleIntrinsic implements WasmGCIntrinsic {
|
||||||
|
private static final long EXPONENT_BITS = 0x7FF0000000000000L;
|
||||||
|
private static final long FRACTION_BITS = 0x000FFFFFFFFFFFFFL;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "getNaN":
|
||||||
|
return new WasmFloat64Constant(Double.NaN);
|
||||||
|
case "isNaN":
|
||||||
|
return testNaN(context.generate(invocation.getArguments().get(0)), context);
|
||||||
|
case "isInfinite":
|
||||||
|
return testIsInfinite(context.generate(invocation.getArguments().get(0)));
|
||||||
|
case "isFinite":
|
||||||
|
return testIsFinite(context.generate(invocation.getArguments().get(0)));
|
||||||
|
case "doubleToRawLongBits": {
|
||||||
|
WasmConversion conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false,
|
||||||
|
context.generate(invocation.getArguments().get(0)));
|
||||||
|
conversion.setReinterpret(true);
|
||||||
|
return conversion;
|
||||||
|
}
|
||||||
|
case "longBitsToDouble": {
|
||||||
|
WasmConversion conversion = new WasmConversion(WasmNumType.INT64, WasmNumType.FLOAT64, false,
|
||||||
|
context.generate(invocation.getArguments().get(0)));
|
||||||
|
conversion.setReinterpret(true);
|
||||||
|
return conversion;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression testNaN(WasmExpression expression, WasmGCIntrinsicContext context) {
|
||||||
|
var block = new WasmBlock(false);
|
||||||
|
block.setType(WasmType.INT32);
|
||||||
|
var cache = context.exprCache().create(expression, WasmType.FLOAT64, expression.getLocation(),
|
||||||
|
block.getBody());
|
||||||
|
block.getBody().add(new WasmFloatBinary(WasmFloatType.FLOAT64, WasmFloatBinaryOperation.NE,
|
||||||
|
cache.expr(), cache.expr()));
|
||||||
|
cache.release();
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression testIsInfinite(WasmExpression expression) {
|
||||||
|
var conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
|
||||||
|
conversion.setReinterpret(true);
|
||||||
|
|
||||||
|
var result = new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.AND,
|
||||||
|
conversion, new WasmInt64Constant(EXPONENT_BITS));
|
||||||
|
return new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.EQ, result,
|
||||||
|
new WasmInt64Constant(EXPONENT_BITS));
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression testIsFinite(WasmExpression expression) {
|
||||||
|
var conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
|
||||||
|
conversion.setReinterpret(true);
|
||||||
|
|
||||||
|
var result = new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.AND,
|
||||||
|
conversion, new WasmInt64Constant(EXPONENT_BITS));
|
||||||
|
return new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.NE, result,
|
||||||
|
new WasmInt64Constant(EXPONENT_BITS));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 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.backend.wasm.intrinsics.gc;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmFloat32Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmFloatBinary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
|
|
||||||
|
public class FloatIntrinsic implements WasmGCIntrinsic {
|
||||||
|
private static final int EXPONENT_BITS = 0x7F800000;
|
||||||
|
private static final int FRACTION_BITS = 0x007FFFFF;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext manager) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "getNaN":
|
||||||
|
return new WasmFloat32Constant(Float.NaN);
|
||||||
|
case "isNaN":
|
||||||
|
return testNaN(manager.generate(invocation.getArguments().get(0)), manager);
|
||||||
|
case "isInfinite":
|
||||||
|
return testIsInfinite(manager.generate(invocation.getArguments().get(0)));
|
||||||
|
case "isFinite":
|
||||||
|
return testIsFinite(manager.generate(invocation.getArguments().get(0)));
|
||||||
|
case "floatToRawIntBits": {
|
||||||
|
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false,
|
||||||
|
manager.generate(invocation.getArguments().get(0)));
|
||||||
|
conversion.setReinterpret(true);
|
||||||
|
return conversion;
|
||||||
|
}
|
||||||
|
case "intBitsToFloat": {
|
||||||
|
var conversion = new WasmConversion(WasmNumType.INT32, WasmNumType.FLOAT32, false,
|
||||||
|
manager.generate(invocation.getArguments().get(0)));
|
||||||
|
conversion.setReinterpret(true);
|
||||||
|
return conversion;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression testNaN(WasmExpression expression, WasmGCIntrinsicContext context) {
|
||||||
|
var block = new WasmBlock(false);
|
||||||
|
block.setType(WasmType.INT32);
|
||||||
|
var cache = context.exprCache().create(expression, WasmType.FLOAT32, expression.getLocation(),
|
||||||
|
block.getBody());
|
||||||
|
block.getBody().add(new WasmFloatBinary(WasmFloatType.FLOAT32, WasmFloatBinaryOperation.NE,
|
||||||
|
cache.expr(), cache.expr()));
|
||||||
|
cache.release();
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression testIsInfinite(WasmExpression expression) {
|
||||||
|
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
|
||||||
|
conversion.setReinterpret(true);
|
||||||
|
|
||||||
|
var result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND,
|
||||||
|
conversion, new WasmInt32Constant(EXPONENT_BITS));
|
||||||
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ, result,
|
||||||
|
new WasmInt32Constant(EXPONENT_BITS));
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression testIsFinite(WasmExpression expression) {
|
||||||
|
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
|
||||||
|
conversion.setReinterpret(true);
|
||||||
|
|
||||||
|
var result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND,
|
||||||
|
conversion, new WasmInt32Constant(EXPONENT_BITS));
|
||||||
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.NE, result,
|
||||||
|
new WasmInt32Constant(EXPONENT_BITS));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 konsoletyper.
|
||||||
|
*
|
||||||
|
* 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.backend.wasm.intrinsics.gc;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.backend.wasm.model.WasmNumType;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
|
||||||
|
public class SystemIntrinsic implements WasmGCIntrinsic {
|
||||||
|
private WasmFunction workerFunction;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
|
if (workerFunction == null) {
|
||||||
|
workerFunction = new WasmFunction(context.functionTypes().of(WasmType.FLOAT64));
|
||||||
|
workerFunction.setName("teavm@currentTimeMillis");
|
||||||
|
workerFunction.setImportName("currentTimeMillis");
|
||||||
|
workerFunction.setImportModule("teavm");
|
||||||
|
context.module().functions.add(workerFunction);
|
||||||
|
}
|
||||||
|
var call = new WasmCall(workerFunction);
|
||||||
|
return new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, true, call);
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,8 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
fillClass();
|
fillClass();
|
||||||
fillSystem();
|
fillSystem();
|
||||||
fillLongAndInteger();
|
fillLongAndInteger();
|
||||||
|
fillFloat();
|
||||||
|
fillDouble();
|
||||||
fillArray();
|
fillArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +78,8 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
private void fillSystem() {
|
private void fillSystem() {
|
||||||
intrinsics.put(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class,
|
intrinsics.put(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class,
|
||||||
int.class, int.class, void.class), new SystemArrayCopyIntrinsic());
|
int.class, int.class, void.class), new SystemArrayCopyIntrinsic());
|
||||||
|
intrinsics.put(new MethodReference(System.class, "currentTimeMillis", long.class),
|
||||||
|
new SystemIntrinsic());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillLongAndInteger() {
|
private void fillLongAndInteger() {
|
||||||
|
@ -93,6 +97,26 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
intrinsic);
|
intrinsic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillFloat() {
|
||||||
|
var intrinsic = new FloatIntrinsic();
|
||||||
|
intrinsics.put(new MethodReference(Float.class, "getNaN", float.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Float.class, "isNaN", float.class, boolean.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Float.class, "isInfinite", float.class, boolean.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Float.class, "isFinite", float.class, boolean.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Float.class, "floatToRawIntBits", float.class, int.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Float.class, "intBitsToFloat", int.class, float.class), intrinsic);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillDouble() {
|
||||||
|
var intrinsic = new DoubleIntrinsic();
|
||||||
|
intrinsics.put(new MethodReference(Double.class, "getNaN", double.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Double.class, "isNaN", double.class, boolean.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Double.class, "isInfinite", double.class, boolean.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Double.class, "isFinite", double.class, boolean.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Double.class, "doubleToRawLongBits", double.class, long.class), intrinsic);
|
||||||
|
intrinsics.put(new MethodReference(Double.class, "longBitsToDouble", long.class, double.class), intrinsic);
|
||||||
|
}
|
||||||
|
|
||||||
private void fillArray() {
|
private void fillArray() {
|
||||||
var intrinsic = new ArrayIntrinsic();
|
var intrinsic = new ArrayIntrinsic();
|
||||||
intrinsics.put(new MethodReference(Array.class, "getLength", Object.class, int.class), intrinsic);
|
intrinsics.put(new MethodReference(Array.class, "getLength", Object.class, int.class), intrinsic);
|
||||||
|
|
|
@ -60,8 +60,10 @@ public class WasmFunction extends WasmEntity {
|
||||||
|
|
||||||
public void setImportName(String importName) {
|
public void setImportName(String importName) {
|
||||||
this.importName = importName;
|
this.importName = importName;
|
||||||
|
if (collection != null) {
|
||||||
collection.invalidateIndexes();
|
collection.invalidateIndexes();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String getImportModule() {
|
public String getImportModule() {
|
||||||
return importModule;
|
return importModule;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user