From d0226aab8802f353397659f6bfe815b9cdd14207 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 8 Sep 2024 20:32:30 +0200 Subject: [PATCH] wasm gc: implement some Class intrinsics, fix issues with type inference --- .../org/teavm/classlib/java/lang/TClass.java | 8 +++-- .../ast/optimization/OptimizingVisitor.java | 2 +- .../org/teavm/backend/wasm/gc/WasmGCUtil.java | 6 ++-- .../gc/classes/WasmGCClassGenerator.java | 24 +++++++++++++- .../gc/classes/WasmGCClassInfoProvider.java | 4 +++ ...assIntrinsics.java => ClassIntrinsic.java} | 31 +++++++++++++++++-- .../wasm/intrinsics/gc/WasmGCIntrinsics.java | 5 ++- .../gc/BaseClassesTransformation.java | 3 ++ 8 files changed, 73 insertions(+), 10 deletions(-) rename core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/{ClassIntrinsics.java => ClassIntrinsic.java} (61%) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 413b1b5b5..afc2c3acd 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -164,12 +164,16 @@ public final class TClass extends TObject implements TAnnotatedElement, TType if (isArray()) { simpleName = getComponentType().getSimpleName() + "[]"; } else if (getEnclosingClass() != null) { - simpleName = Platform.getSimpleName(platformClass); + simpleName = PlatformDetector.isWebAssemblyGC() + ? getSimpleNameCache(this) + : Platform.getSimpleName(platformClass); if (simpleName == null) { simpleName = ""; } } else { - String name = Platform.getName(platformClass); + var name = PlatformDetector.isWebAssemblyGC() + ? getName() + : Platform.getName(platformClass); int lastDollar = name.lastIndexOf('$'); if (lastDollar != -1) { name = name.substring(lastDollar + 1); diff --git a/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java b/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java index f021065b4..eb1bf7790 100644 --- a/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java +++ b/core/src/main/java/org/teavm/ast/optimization/OptimizingVisitor.java @@ -1097,7 +1097,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { conditionalExpr.setConsequent(firstAssignment.getRightValue()); conditionalExpr.setAlternative(secondAssignment.getRightValue()); conditionalExpr.setLocation(statement.getCondition().getLocation()); - conditionalExpr.setVariableIndex(firstAssignment.getRightValue().getVariableIndex()); + conditionalExpr.setVariableIndex(firstAssignment.getLeftValue().getVariableIndex()); AssignmentStatement assignment = new AssignmentStatement(); assignment.setLocation(conditionalExpr.getLocation()); VariableExpr lhs = new VariableExpr(); diff --git a/core/src/main/java/org/teavm/backend/wasm/gc/WasmGCUtil.java b/core/src/main/java/org/teavm/backend/wasm/gc/WasmGCUtil.java index dfbee2dea..43ca4dff8 100644 --- a/core/src/main/java/org/teavm/backend/wasm/gc/WasmGCUtil.java +++ b/core/src/main/java/org/teavm/backend/wasm/gc/WasmGCUtil.java @@ -34,9 +34,9 @@ public final class WasmGCUtil { if (firstPath.get(0) != secondPath.get(0)) { return "java.lang.Object"; } - var min = Math.min(firstPath.size(), secondPath.size()); - var index = 1; - while (index < min && firstPath.get(index) == secondPath.get(index)) { + var min = Math.min(firstPath.size(), secondPath.size()) - 1; + var index = 0; + while (index < min && firstPath.get(index + 1) == secondPath.get(index + 1)) { ++index; } return index < firstPath.size() ? firstPath.get(index).getName() : secondPath.get(index).getName(); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java index 0a29442a0..8679a3efe 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java @@ -119,11 +119,13 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit private int classTagOffset; private int classFlagsOffset; private int classNameOffset; + private int classSimpleNameOffset; private int classParentOffset; private int classArrayOffset; private int classArrayItemOffset; private int classNewArrayOffset; private int classSupertypeFunctionOffset; + private int classEnclosingClassOffset; private int virtualTableFieldOffset; private int arrayLengthOffset = -1; private int arrayGetOffset = -1; @@ -351,12 +353,24 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit return classSupertypeFunctionOffset; } + @Override + public int getClassEnclosingClassOffset() { + standardClasses.classClass().getStructure().init(); + return classEnclosingClassOffset; + } + @Override public int getClassNameOffset() { standardClasses.classClass().getStructure().init(); return classNameOffset; } + @Override + public int getClassSimpleNameOffset() { + standardClasses.classClass().getStructure().init(); + return classSimpleNameOffset; + } + @Override public int getNewArrayFunctionOffset() { standardClasses.classClass().getStructure().init(); @@ -445,12 +459,16 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit if (cls != null) { if (metadataReq.simpleName() && cls.getSimpleName() != null) { var namePtr = strings.getStringConstant(cls.getSimpleName()).global; - target.add(setClassField(classInfo, classNameOffset, new WasmGetGlobal(namePtr))); + target.add(setClassField(classInfo, classSimpleNameOffset, new WasmGetGlobal(namePtr))); } if (cls.getParent() != null && metadataReq.superclass()) { var parent = getClassInfo(cls.getParent()); target.add(setClassField(classInfo, classParentOffset, new WasmGetGlobal(parent.pointer))); } + if (cls.getOwnerName() != null && metadataReq.superclass()) { + var owner = getClassInfo(cls.getOwnerName()); + target.add(setClassField(classInfo, classEnclosingClassOffset, new WasmGetGlobal(owner.pointer))); + } } if (virtualTable != null && virtualTable.isConcrete()) { fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable); @@ -960,8 +978,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit classNewArrayOffset = fields.size(); fields.add(createClassField(newArrayGenerator.getNewArrayFunctionType().getReference().asStorage(), "createArrayInstance")); + classEnclosingClassOffset = fields.size(); + fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "enclosingClass")); classNameOffset = fields.size(); fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "name")); + classSimpleNameOffset = fields.size(); + fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "simpleNAme")); virtualTableFieldOffset = fields.size(); } } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java index 714df47a2..7a537471b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassInfoProvider.java @@ -40,10 +40,14 @@ public interface WasmGCClassInfoProvider { int getClassSupertypeFunctionOffset(); + int getClassEnclosingClassOffset(); + int getNewArrayFunctionOffset(); int getClassNameOffset(); + int getClassSimpleNameOffset(); + int getArrayGetOffset(); int getArrayLengthOffset(); diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsics.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsic.java similarity index 61% rename from core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsics.java rename to core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsic.java index def726133..94c232633 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsics.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ClassIntrinsic.java @@ -20,21 +20,34 @@ 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 { +public class ClassIntrinsic implements WasmGCIntrinsic { @Override public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) { switch (invocation.getMethod().getName()) { - case "getComponentType": + case "getComponentType": { var cls = context.generate(invocation.getArguments().get(0)); var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure(); var result = new WasmStructGet(clsStruct, cls, context.classInfoProvider().getClassArrayItemOffset()); result.setLocation(invocation.getLocation()); return result; + } + case "getEnclosingClass": { + var cls = context.generate(invocation.getArguments().get(0)); + var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure(); + var result = new WasmStructGet(clsStruct, cls, + context.classInfoProvider().getClassEnclosingClassOffset()); + result.setLocation(invocation.getLocation()); + return result; + } case "getNameImpl": return generateGetName(invocation, context); case "setNameImpl": return generateSetName(invocation, context); + case "getSimpleNameCache": + return generateGetSimpleName(invocation, context); + case "setSimpleNameCache": + return generateSetSimpleName(invocation, context); default: throw new IllegalArgumentException("Unsupported invocation method: " + invocation.getMethod()); } @@ -53,4 +66,18 @@ public class ClassIntrinsics implements WasmGCIntrinsic { return new WasmStructSet(classCls.getStructure(), arg, context.classInfoProvider().getClassNameOffset(), value); } + + private WasmExpression generateGetSimpleName(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().getClassSimpleNameOffset()); + } + + private WasmExpression generateSetSimpleName(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().getClassSimpleNameOffset(), value); + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java index 5dd989000..bd664d980 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java @@ -78,10 +78,13 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider { } private void fillClass() { - var intrinsic = new ClassIntrinsics(); + var intrinsic = new ClassIntrinsic(); add(new MethodReference(Class.class, "getComponentType", Class.class), intrinsic); add(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic); add(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic); + add(new MethodReference(Class.class, "getEnclosingClass", Class.class), intrinsic); + add(new MethodReference(Class.class, "getSimpleNameCache", Class.class, String.class), intrinsic); + add(new MethodReference(Class.class, "setSimpleNameCache", Class.class, String.class, void.class), intrinsic); } private void fillSystem() { diff --git a/core/src/main/java/org/teavm/backend/wasm/transformation/gc/BaseClassesTransformation.java b/core/src/main/java/org/teavm/backend/wasm/transformation/gc/BaseClassesTransformation.java index 2d53cf891..ca9bb7b30 100644 --- a/core/src/main/java/org/teavm/backend/wasm/transformation/gc/BaseClassesTransformation.java +++ b/core/src/main/java/org/teavm/backend/wasm/transformation/gc/BaseClassesTransformation.java @@ -77,6 +77,9 @@ public class BaseClassesTransformation implements ClassHolderTransformer { switch (method.getName()) { case "getComponentType": case "isInstance": + case "getEnclosingClass": + case "getSimpleNameCache": + case "setSimpleNameCache": method.setProgram(null); method.getModifiers().add(ElementModifier.NATIVE); break;