Address intrinsic (partial)

This commit is contained in:
lax1dude 2024-11-01 21:06:05 -07:00
parent 7d8f5fc9c4
commit 0d8baace3d
3 changed files with 208 additions and 27 deletions

View File

@ -0,0 +1,157 @@
/*
* Copyright 2024 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 java.util.stream.Collectors;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.WasmRuntime;
import org.teavm.backend.wasm.model.WasmNumType;
import org.teavm.backend.wasm.model.expression.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmConversion;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
import org.teavm.backend.wasm.model.expression.WasmIntType;
import org.teavm.backend.wasm.model.expression.WasmLoadFloat32;
import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
import org.teavm.backend.wasm.model.expression.WasmLoadInt64;
import org.teavm.backend.wasm.model.expression.WasmStoreFloat32;
import org.teavm.backend.wasm.model.expression.WasmStoreFloat64;
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class AddressIntrinsic implements WasmGCIntrinsic {
@Override
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext manager) {
switch (invocation.getMethod().getName()) {
case "toInt":
case "toStructure":
return manager.generate(invocation.getArguments().get(0));
case "toLong": {
WasmExpression value = manager.generate(invocation.getArguments().get(0));
return new WasmConversion(WasmNumType.INT32, WasmNumType.INT64, false, value);
}
case "fromInt":
return manager.generate(invocation.getArguments().get(0));
case "fromLong": {
WasmExpression value = manager.generate(invocation.getArguments().get(0));
return new WasmConversion(WasmNumType.INT64, WasmNumType.INT32, false, value);
}
case "add": {
WasmExpression base = manager.generate(invocation.getArguments().get(0));
if (invocation.getMethod().parameterCount() == 1) {
WasmExpression offset = manager.generate(invocation.getArguments().get(1));
if (invocation.getMethod().parameterType(0) == ValueType.LONG) {
offset = new WasmConversion(WasmNumType.INT64, WasmNumType.INT32, false, offset);
}
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
} else {
throw new IllegalArgumentException(invocation.getMethod().toString());
}
}
case "getByte":
return new WasmLoadInt32(1, manager.generate(invocation.getArguments().get(0)),
WasmInt32Subtype.INT8);
case "getShort":
return new WasmLoadInt32(2, manager.generate(invocation.getArguments().get(0)),
WasmInt32Subtype.INT16);
case "getChar":
return new WasmLoadInt32(2, manager.generate(invocation.getArguments().get(0)),
WasmInt32Subtype.UINT16);
case "getAddress":
case "getInt":
return new WasmLoadInt32(4, manager.generate(invocation.getArguments().get(0)),
WasmInt32Subtype.INT32);
case "getLong":
return new WasmLoadInt64(8, manager.generate(invocation.getArguments().get(0)),
WasmInt64Subtype.INT64);
case "getFloat":
return new WasmLoadFloat32(4, manager.generate(invocation.getArguments().get(0)));
case "getDouble":
return new WasmLoadFloat64(8, manager.generate(invocation.getArguments().get(0)));
case "putByte": {
WasmExpression address = manager.generate(invocation.getArguments().get(0));
WasmExpression value = manager.generate(invocation.getArguments().get(1));
return new WasmStoreInt32(1, address, value, WasmInt32Subtype.INT8);
}
case "putShort": {
WasmExpression address = manager.generate(invocation.getArguments().get(0));
WasmExpression value = manager.generate(invocation.getArguments().get(1));
return new WasmStoreInt32(2, address, value, WasmInt32Subtype.INT16);
}
case "putChar": {
WasmExpression address = manager.generate(invocation.getArguments().get(0));
WasmExpression value = manager.generate(invocation.getArguments().get(1));
return new WasmStoreInt32(2, address, value, WasmInt32Subtype.UINT16);
}
case "putAddress":
case "putInt": {
WasmExpression address = manager.generate(invocation.getArguments().get(0));
WasmExpression value = manager.generate(invocation.getArguments().get(1));
return new WasmStoreInt32(4, address, value, WasmInt32Subtype.INT32);
}
case "putLong": {
WasmExpression address = manager.generate(invocation.getArguments().get(0));
WasmExpression value = manager.generate(invocation.getArguments().get(1));
return new WasmStoreInt64(8, address, value, WasmInt64Subtype.INT64);
}
case "putFloat": {
WasmExpression address = manager.generate(invocation.getArguments().get(0));
WasmExpression value = manager.generate(invocation.getArguments().get(1));
return new WasmStoreFloat32(4, address, value);
}
case "putDouble": {
WasmExpression address = manager.generate(invocation.getArguments().get(0));
WasmExpression value = manager.generate(invocation.getArguments().get(1));
return new WasmStoreFloat64(8, address, value);
}
case "sizeOf":
return new WasmInt32Constant(4);
case "align": {
MethodReference delegate = new MethodReference(WasmRuntime.class.getName(),
invocation.getMethod().getDescriptor());
WasmCall call = new WasmCall(manager.functions().forStaticMethod(delegate));
call.getArguments().addAll(invocation.getArguments().stream()
.map(arg -> manager.generate(arg))
.collect(Collectors.toList()));
return call;
}
case "isLessThan":
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_UNSIGNED,
manager.generate(invocation.getArguments().get(0)),
manager.generate(invocation.getArguments().get(1)));
case "diff": {
WasmExpression result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SUB,
manager.generate(invocation.getArguments().get(0)),
manager.generate(invocation.getArguments().get(1))
);
result = new WasmConversion(WasmNumType.INT32, WasmNumType.INT64, true, result);
result.setLocation(invocation.getLocation());
return result;
}
default:
throw new IllegalArgumentException(invocation.getMethod().toString());
}
}
}

View File

@ -16,8 +16,6 @@
package org.teavm.backend.wasm.intrinsics.gc; package org.teavm.backend.wasm.intrinsics.gc;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
import org.teavm.backend.wasm.model.expression.WasmCall; import org.teavm.backend.wasm.model.expression.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmCopy; import org.teavm.backend.wasm.model.expression.WasmCopy;
import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpression;
@ -25,11 +23,10 @@ import org.teavm.backend.wasm.model.expression.WasmFill;
import org.teavm.backend.wasm.model.expression.WasmInt32Constant; import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
import org.teavm.backend.wasm.model.expression.WasmUnreachable; import org.teavm.backend.wasm.model.expression.WasmUnreachable;
import org.teavm.interop.Address; import org.teavm.interop.Address;
import org.teavm.interop.DirectMalloc;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.runtime.LaxMalloc; import org.teavm.runtime.LaxMalloc;
public class DirectMallocIntrinsic implements WasmIntrinsic { public class DirectMallocIntrinsic implements WasmGCIntrinsic {
private static final MethodReference LAX_MALLOC = new MethodReference(LaxMalloc.class, "laxMalloc", int.class, private static final MethodReference LAX_MALLOC = new MethodReference(LaxMalloc.class, "laxMalloc", int.class,
Address.class); Address.class);
private static final MethodReference LAX_CALLOC = new MethodReference(LaxMalloc.class, "laxCalloc", int.class, private static final MethodReference LAX_CALLOC = new MethodReference(LaxMalloc.class, "laxCalloc", int.class,
@ -38,41 +35,22 @@ public class DirectMallocIntrinsic implements WasmIntrinsic {
void.class); void.class);
@Override @Override
public boolean isApplicable(MethodReference methodReference) { public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext manager) {
if (!methodReference.getClassName().equals(DirectMalloc.class.getName())) {
return false;
}
switch (methodReference.getName()) {
case "malloc":
case "calloc":
case "free":
case "memcpy":
case "memset":
case "zmemset":
return true;
default:
return false;
}
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) { switch (invocation.getMethod().getName()) {
case "malloc": { case "malloc": {
var function = manager.getFunctions().forStaticMethod(LAX_MALLOC); var function = manager.functions().forStaticMethod(LAX_MALLOC);
var call = new WasmCall(function); var call = new WasmCall(function);
call.getArguments().add(manager.generate(invocation.getArguments().get(0))); call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
return call; return call;
} }
case "calloc": { case "calloc": {
var function = manager.getFunctions().forStaticMethod(LAX_CALLOC); var function = manager.functions().forStaticMethod(LAX_CALLOC);
var call = new WasmCall(function); var call = new WasmCall(function);
call.getArguments().add(manager.generate(invocation.getArguments().get(0))); call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
return call; return call;
} }
case "free": { case "free": {
var function = manager.getFunctions().forStaticMethod(LAX_FREE); var function = manager.functions().forStaticMethod(LAX_FREE);
var call = new WasmCall(function); var call = new WasmCall(function);
call.getArguments().add(manager.generate(invocation.getArguments().get(0))); call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
return call; return call;

View File

@ -25,6 +25,8 @@ import org.teavm.backend.wasm.model.expression.WasmIntType;
import org.teavm.backend.wasm.runtime.StringInternPool; import org.teavm.backend.wasm.runtime.StringInternPool;
import org.teavm.backend.wasm.runtime.gc.WasmGCResources; import org.teavm.backend.wasm.runtime.gc.WasmGCResources;
import org.teavm.common.ServiceRepository; import org.teavm.common.ServiceRepository;
import org.teavm.interop.Address;
import org.teavm.interop.DirectMalloc;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
@ -51,6 +53,8 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
fillArray(); fillArray();
fillString(); fillString();
fillResources(); fillResources();
fillDirectMalloc();
fillAddress();
for (var entry : customIntrinsics.entrySet()) { for (var entry : customIntrinsics.entrySet()) {
add(entry.getKey(), entry.getValue()); add(entry.getKey(), entry.getValue());
} }
@ -166,6 +170,48 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
add(new MethodReference(WasmGCResources.class, "readSingleByte", int.class, int.class), intrinsic); add(new MethodReference(WasmGCResources.class, "readSingleByte", int.class, int.class), intrinsic);
} }
private void fillDirectMalloc() {
var intrinsic = new DirectMallocIntrinsic();
add(new MethodReference(DirectMalloc.class, "malloc", int.class, Address.class), intrinsic);
add(new MethodReference(DirectMalloc.class, "calloc", int.class, Address.class), intrinsic);
add(new MethodReference(DirectMalloc.class, "free", Address.class, void.class), intrinsic);
add(new MethodReference(DirectMalloc.class, "memcpy", Address.class, Address.class, int.class, void.class), intrinsic);
add(new MethodReference(DirectMalloc.class, "memset", Address.class, int.class, int.class, void.class), intrinsic);
add(new MethodReference(DirectMalloc.class, "zmemset", Address.class, int.class, void.class), intrinsic);
}
private void fillAddress() {
var intrinsic = new AddressIntrinsic();
add(new MethodReference(Address.class, "add", int.class, Address.class), intrinsic);
add(new MethodReference(Address.class, "add", long.class, Address.class), intrinsic);
add(new MethodReference(Address.class, "isLessThan", Address.class, boolean.class), intrinsic);
add(new MethodReference(Address.class, "toInt", int.class), intrinsic);
add(new MethodReference(Address.class, "toLong", long.class), intrinsic);
//add(new MethodReference(Address.class, "toStructure", ?????), intrinsic); //TODO
add(new MethodReference(Address.class, "getByte", byte.class), intrinsic);
add(new MethodReference(Address.class, "putByte", byte.class, void.class), intrinsic);
add(new MethodReference(Address.class, "getChar", char.class), intrinsic);
add(new MethodReference(Address.class, "putChar", char.class, void.class), intrinsic);
add(new MethodReference(Address.class, "getShort", short.class), intrinsic);
add(new MethodReference(Address.class, "putShort", short.class, void.class), intrinsic);
add(new MethodReference(Address.class, "getInt", int.class), intrinsic);
add(new MethodReference(Address.class, "putInt", int.class, void.class), intrinsic);
add(new MethodReference(Address.class, "getLong", long.class), intrinsic);
add(new MethodReference(Address.class, "putLong", long.class, void.class), intrinsic);
add(new MethodReference(Address.class, "getFloat", float.class), intrinsic);
add(new MethodReference(Address.class, "putFloat", float.class, void.class), intrinsic);
add(new MethodReference(Address.class, "getDouble", double.class), intrinsic);
add(new MethodReference(Address.class, "putDouble", double.class, void.class), intrinsic);
add(new MethodReference(Address.class, "getAddress", Address.class), intrinsic);
add(new MethodReference(Address.class, "putAddress", Address.class, void.class), intrinsic);
add(new MethodReference(Address.class, "fromInt", int.class, Address.class), intrinsic);
add(new MethodReference(Address.class, "fromLong", long.class, Address.class), intrinsic);
add(new MethodReference(Address.class, "align", Address.class, int.class, Address.class), intrinsic);
add(new MethodReference(Address.class, "sizeOf", int.class), intrinsic);
add(new MethodReference(Address.class, "add", Class.class, int.class), intrinsic);
add(new MethodReference(Address.class, "diff", Address.class, long.class), intrinsic);
}
private void add(MethodReference methodRef, WasmGCIntrinsic intrinsic) { private void add(MethodReference methodRef, WasmGCIntrinsic intrinsic) {
intrinsics.put(methodRef, new IntrinsicContainer(intrinsic)); intrinsics.put(methodRef, new IntrinsicContainer(intrinsic));
} }