mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
wasm gc: implement intrinsics for Long and Class classes
This commit is contained in:
parent
a97e6574ac
commit
5eb1e7d9bc
|
@ -117,7 +117,20 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
|
|||
}
|
||||
|
||||
public String getName() {
|
||||
if (PlatformDetector.isLowLevel()) {
|
||||
if (PlatformDetector.isWebAssemblyGC()) {
|
||||
var result = getNameImpl();
|
||||
if (result == null) {
|
||||
if (isArray()) {
|
||||
var componentType = getComponentType();
|
||||
String componentName = componentType.getName();
|
||||
if (componentName != null) {
|
||||
result = componentType.isArray() ? "[" + componentName : "[L" + componentName + ";";
|
||||
setNameImpl(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else if (PlatformDetector.isLowLevel()) {
|
||||
String result = getNameCache(this);
|
||||
if (result == null) {
|
||||
result = Platform.getName(platformClass);
|
||||
|
@ -141,6 +154,10 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
|
|||
}
|
||||
}
|
||||
|
||||
private native String getNameImpl();
|
||||
|
||||
private native void setNameImpl(String name);
|
||||
|
||||
public String getSimpleName() {
|
||||
String simpleName = getSimpleNameCache(this);
|
||||
if (simpleName == null) {
|
||||
|
@ -274,6 +291,9 @@ public final class TClass<T> extends TObject implements TAnnotatedElement, TType
|
|||
}
|
||||
|
||||
public boolean isArray() {
|
||||
if (PlatformDetector.isWebAssemblyGC()) {
|
||||
return getComponentType() != null;
|
||||
}
|
||||
return Platform.getArrayItem(platformClass) != null;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.backend.wasm.gc;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||
import org.teavm.dependency.DependencyAnalyzer;
|
||||
|
@ -29,6 +30,7 @@ public class WasmGCDependencies {
|
|||
}
|
||||
|
||||
public void contribute() {
|
||||
contributeWasmRuntime();
|
||||
contributeMathUtils();
|
||||
contributeExceptionUtils();
|
||||
contributeInitializerUtils();
|
||||
|
@ -52,6 +54,21 @@ public class WasmGCDependencies {
|
|||
.use();
|
||||
}
|
||||
|
||||
private void contributeWasmRuntime() {
|
||||
for (var cls : List.of(int.class, long.class, float.class, double.class)) {
|
||||
analyzer.linkMethod(new MethodReference(WasmRuntime.class, "lt", cls, cls, boolean.class)).use();
|
||||
analyzer.linkMethod(new MethodReference(WasmRuntime.class, "gt", cls, cls, boolean.class)).use();
|
||||
}
|
||||
for (var cls : List.of(int.class, long.class)) {
|
||||
analyzer.linkMethod(new MethodReference(WasmRuntime.class, "ltu", cls, cls, boolean.class)).use();
|
||||
analyzer.linkMethod(new MethodReference(WasmRuntime.class, "gtu", cls, cls, boolean.class)).use();
|
||||
}
|
||||
for (var cls : List.of(float.class, double.class)) {
|
||||
analyzer.linkMethod(new MethodReference(WasmRuntime.class, "min", cls, cls, cls)).use();
|
||||
analyzer.linkMethod(new MethodReference(WasmRuntime.class, "max", cls, cls, cls)).use();
|
||||
}
|
||||
}
|
||||
|
||||
private void contributeMathUtils() {
|
||||
for (var type : Arrays.asList(int.class, long.class, float.class, double.class)) {
|
||||
var method = new MethodReference(WasmRuntime.class, "compare", type, type, int.class);
|
||||
|
|
|
@ -455,6 +455,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
var intrinsic = context.intrinsics().get(expr.getMethod());
|
||||
if (intrinsic != null) {
|
||||
var resultExpr = intrinsic.apply(expr, intrinsicContext);
|
||||
resultExpr.setLocation(expr.getLocation());
|
||||
if (resultConsumer != null) {
|
||||
if (willDrop) {
|
||||
var drop = new WasmDrop(resultExpr);
|
||||
|
|
|
@ -36,9 +36,6 @@ public class ClassGenerators implements WasmGCCustomGenerator {
|
|||
case "isInstance":
|
||||
generateIsInstance(function, context);
|
||||
break;
|
||||
case "getName":
|
||||
generateGetName(function, context);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported method: " + method);
|
||||
}
|
||||
|
@ -69,13 +66,4 @@ public class ClassGenerators implements WasmGCCustomGenerator {
|
|||
function.getBody().add(new WasmReturn(conditional));
|
||||
}
|
||||
|
||||
private void generateGetName(WasmFunction function, WasmGCCustomGeneratorContext context) {
|
||||
var classCls = context.classInfoProvider().getClassInfo("java.lang.Class");
|
||||
var thisVar = new WasmLocal(classCls.getType());
|
||||
function.add(thisVar);
|
||||
|
||||
var nameRef = new WasmStructGet(classCls.getStructure(), new WasmGetLocal(thisVar),
|
||||
context.classInfoProvider().getClassNameOffset());
|
||||
function.getBody().add(new WasmReturn(nameRef));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
|||
private void fillClass() {
|
||||
var classGenerators = new ClassGenerators();
|
||||
generators.put(new MethodReference(Class.class, "isInstance", Object.class, boolean.class), classGenerators);
|
||||
generators.put(new MethodReference(Class.class, "getName", String.class), classGenerators);
|
||||
}
|
||||
|
||||
private void fillStringPool() {
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.teavm.backend.wasm.intrinsics.gc;
|
|||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||
|
||||
public class ClassIntrinsics implements WasmGCIntrinsic {
|
||||
@Override
|
||||
|
@ -30,8 +31,26 @@ public class ClassIntrinsics implements WasmGCIntrinsic {
|
|||
context.classInfoProvider().getClassArrayItemOffset());
|
||||
result.setLocation(invocation.getLocation());
|
||||
return result;
|
||||
case "getNameImpl":
|
||||
return generateGetName(invocation, context);
|
||||
case "setNameImpl":
|
||||
return generateSetName(invocation, context);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported invocation method: " + invocation.getMethod());
|
||||
}
|
||||
}
|
||||
|
||||
private WasmExpression generateGetName(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||
var classCls = context.classInfoProvider().getClassInfo("java.lang.Class");
|
||||
var arg = context.generate(invocation.getArguments().get(0));
|
||||
return new WasmStructGet(classCls.getStructure(), arg, context.classInfoProvider().getClassNameOffset());
|
||||
}
|
||||
|
||||
private WasmExpression generateSetName(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||
var classCls = context.classInfoProvider().getClassInfo("java.lang.Class");
|
||||
var arg = context.generate(invocation.getArguments().get(0));
|
||||
var value = context.generate(invocation.getArguments().get(1));
|
||||
return new WasmStructSet(classCls.getStructure(), arg, context.classInfoProvider().getClassNameOffset(),
|
||||
value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
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.model.MethodReference;
|
||||
|
||||
public class LongIntrinsic implements WasmGCIntrinsic {
|
||||
private static final MethodReference COMPARE_UNSIGNED = new MethodReference(WasmRuntime.class,
|
||||
"compareUnsigned", long.class, long.class, int.class);
|
||||
|
||||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "divideUnsigned":
|
||||
return new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.DIV_UNSIGNED,
|
||||
context.generate(invocation.getArguments().get(0)),
|
||||
context.generate(invocation.getArguments().get(1)));
|
||||
case "remainderUnsigned":
|
||||
return new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.REM_UNSIGNED,
|
||||
context.generate(invocation.getArguments().get(0)),
|
||||
context.generate(invocation.getArguments().get(1)));
|
||||
case "compareUnsigned":
|
||||
return new WasmCall(context.functions().forStaticMethod(COMPARE_UNSIGNED),
|
||||
context.generate(invocation.getArguments().get(0)),
|
||||
context.generate(invocation.getArguments().get(1)));
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,9 @@
|
|||
package org.teavm.backend.wasm.intrinsics.gc;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
|
@ -24,9 +26,27 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
|||
private Map<MethodReference, WasmGCIntrinsic> intrinsics = new HashMap<>();
|
||||
|
||||
public WasmGCIntrinsics() {
|
||||
fillWasmRuntime();
|
||||
fillObject();
|
||||
fillClass();
|
||||
fillSystem();
|
||||
fillLong();
|
||||
}
|
||||
|
||||
private void fillWasmRuntime() {
|
||||
var intrinsic = new WasmRuntimeIntrinsic();
|
||||
for (var cls : List.of(int.class, long.class, float.class, double.class)) {
|
||||
intrinsics.put(new MethodReference(WasmRuntime.class, "lt", cls, cls, boolean.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(WasmRuntime.class, "gt", cls, cls, boolean.class), intrinsic);
|
||||
}
|
||||
for (var cls : List.of(int.class, long.class)) {
|
||||
intrinsics.put(new MethodReference(WasmRuntime.class, "ltu", cls, cls, boolean.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(WasmRuntime.class, "gtu", cls, cls, boolean.class), intrinsic);
|
||||
}
|
||||
for (var cls : List.of(float.class, double.class)) {
|
||||
intrinsics.put(new MethodReference(WasmRuntime.class, "min", cls, cls, cls), intrinsic);
|
||||
intrinsics.put(new MethodReference(WasmRuntime.class, "max", cls, cls, cls), intrinsic);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillObject() {
|
||||
|
@ -35,8 +55,10 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
|||
}
|
||||
|
||||
private void fillClass() {
|
||||
var classIntrinsics = new ClassIntrinsics();
|
||||
intrinsics.put(new MethodReference(Class.class, "getComponentType", Class.class), classIntrinsics);
|
||||
var intrinsic = new ClassIntrinsics();
|
||||
intrinsics.put(new MethodReference(Class.class, "getComponentType", Class.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic);
|
||||
}
|
||||
|
||||
private void fillSystem() {
|
||||
|
@ -44,6 +66,16 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
|||
int.class, int.class, void.class), new SystemArrayCopyIntrinsic());
|
||||
}
|
||||
|
||||
private void fillLong() {
|
||||
var intrinsic = new LongIntrinsic();
|
||||
intrinsics.put(new MethodReference(Long.class, "divideUnsigned", long.class, long.class, long.class),
|
||||
intrinsic);
|
||||
intrinsics.put(new MethodReference(Long.class, "remainderUnsigned", long.class, long.class, long.class),
|
||||
intrinsic);
|
||||
intrinsics.put(new MethodReference(Long.class, "compareUnsigned", long.class, long.class, int.class),
|
||||
intrinsic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGCIntrinsic get(MethodReference method) {
|
||||
return intrinsics.get(method);
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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 org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.generate.WasmGeneratorUtil;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
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.WasmIntBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
|
||||
public class WasmRuntimeIntrinsic implements WasmGCIntrinsic {
|
||||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "lt":
|
||||
return comparison(WasmIntBinaryOperation.LT_SIGNED, WasmFloatBinaryOperation.LT,
|
||||
invocation, context);
|
||||
case "gt":
|
||||
return comparison(WasmIntBinaryOperation.GT_SIGNED, WasmFloatBinaryOperation.GT,
|
||||
invocation, context);
|
||||
case "ltu":
|
||||
return comparison(WasmIntBinaryOperation.LT_UNSIGNED, WasmFloatBinaryOperation.LT,
|
||||
invocation, context);
|
||||
case "gtu":
|
||||
return comparison(WasmIntBinaryOperation.GT_UNSIGNED, WasmFloatBinaryOperation.GT,
|
||||
invocation, context);
|
||||
case "min":
|
||||
return comparison(WasmIntBinaryOperation.GT_SIGNED, WasmFloatBinaryOperation.MIN,
|
||||
invocation, context);
|
||||
case "max":
|
||||
return comparison(WasmIntBinaryOperation.GT_SIGNED, WasmFloatBinaryOperation.MAX,
|
||||
invocation, context);
|
||||
default:
|
||||
throw new IllegalArgumentException(invocation.getMethod().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static WasmExpression comparison(WasmIntBinaryOperation intOp, WasmFloatBinaryOperation floatOp,
|
||||
InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||
var type = (WasmType.Number) WasmGeneratorUtil.mapType(invocation.getMethod().parameterType(0));
|
||||
|
||||
WasmExpression first = context.generate(invocation.getArguments().get(0));
|
||||
WasmExpression second = context.generate(invocation.getArguments().get(1));
|
||||
|
||||
switch (type.number) {
|
||||
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);
|
||||
default:
|
||||
throw new IllegalArgumentException(type.toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,21 +74,6 @@ public class VirtualTable {
|
|||
}
|
||||
|
||||
public boolean hasValidEntries() {
|
||||
if (!hasValidEntriesComputed) {
|
||||
hasValidEntriesComputed = true;
|
||||
hasValidEntries = false;
|
||||
if (entryMap != null) {
|
||||
for (var entry : entryMap.values()) {
|
||||
if (entry.getImplementor() != null) {
|
||||
hasValidEntries = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parent != null && parent.hasValidEntries()) {
|
||||
hasValidEntries = true;
|
||||
}
|
||||
}
|
||||
return hasValidEntries;
|
||||
return !methods.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user