From e61301576b3bfc3951db89a4156a3887394caaca Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 3 Aug 2024 20:59:19 +0200 Subject: [PATCH] wasm gc: support System.arrayCopy for special cases --- .../org/teavm/backend/wasm/WasmGCTarget.java | 10 +- .../gc/WasmGCDeclarationsGenerator.java | 7 +- .../gc/classes/WasmGCClassGenerator.java | 2 +- .../gc/methods/WasmGCGenerationContext.java | 24 +++- .../gc/methods/WasmGCGenerationVisitor.java | 70 ++++++++++++ .../gc/methods/WasmGCIntrinsicProvider.java | 23 ++++ .../gc/methods/WasmGCMethodGenerator.java | 14 ++- .../gc/SystemDoArrayCopyGenerator.java | 35 ++++++ .../gc/WasmGCCustomGeneratorContext.java | 3 + .../generators/gc/WasmGCCustomGenerators.java | 9 ++ .../gc/SystemArrayCopyIntrinsic.java | 103 ++++++++++++++++++ .../wasm/intrinsics/gc/WasmGCIntrinsic.java | 23 ++++ .../intrinsics/gc/WasmGCIntrinsicContext.java | 41 +++++++ .../wasm/intrinsics/gc/WasmGCIntrinsics.java | 39 +++++++ .../model/analysis/BaseTypeInference.java | 8 +- core/src/main/java/org/teavm/vm/TeaVM.java | 4 +- .../main/java/org/teavm/vm/TeaVMTarget.java | 4 + 17 files changed, 405 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCIntrinsicProvider.java create mode 100644 core/src/main/java/org/teavm/backend/wasm/generators/gc/SystemDoArrayCopyGenerator.java create mode 100644 core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/SystemArrayCopyIntrinsic.java create mode 100644 core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsic.java create mode 100644 core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsicContext.java create mode 100644 core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java index 5f418fbf6..60bdd532d 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java @@ -20,6 +20,7 @@ import java.util.List; import org.teavm.backend.wasm.gc.WasmGCDependencies; import org.teavm.backend.wasm.generate.gc.WasmGCDeclarationsGenerator; import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerators; +import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsics; import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.render.WasmBinaryRenderer; import org.teavm.backend.wasm.render.WasmBinaryStatsCollector; @@ -108,6 +109,7 @@ public class WasmGCTarget implements TeaVMTarget { public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException { var module = new WasmModule(); var customGenerators = new WasmGCCustomGenerators(); + var intrinsics = new WasmGCIntrinsics(); var declarationsGenerator = new WasmGCDeclarationsGenerator( module, classes, @@ -115,7 +117,8 @@ public class WasmGCTarget implements TeaVMTarget { controller.getClassInitializerInfo(), controller.getDependencyInfo(), controller.getDiagnostics(), - customGenerators + customGenerators, + intrinsics ); declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger()); var moduleGenerator = new WasmGCModuleGenerator(declarationsGenerator); @@ -156,4 +159,9 @@ public class WasmGCTarget implements TeaVMTarget { output.write(data); } } + + @Override + public boolean needsSystemArrayCopyOptimization() { + return false; + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCDeclarationsGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCDeclarationsGenerator.java index 391409805..ad777268c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCDeclarationsGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/WasmGCDeclarationsGenerator.java @@ -26,6 +26,7 @@ import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCSupertypeFunctionProvider; import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper; import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider; +import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider; import org.teavm.backend.wasm.generate.gc.methods.WasmGCMethodGenerator; import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmModule; @@ -55,7 +56,8 @@ public class WasmGCDeclarationsGenerator { ClassInitializerInfo classInitializerInfo, DependencyInfo dependencyInfo, Diagnostics diagnostics, - WasmGCCustomGeneratorProvider customGenerators + WasmGCCustomGeneratorProvider customGenerators, + WasmGCIntrinsicProvider intrinsics ) { this.module = module; hierarchy = new ClassHierarchy(classes); @@ -73,7 +75,8 @@ public class WasmGCDeclarationsGenerator { names, diagnostics, returnTypes, - customGenerators + customGenerators, + intrinsics ); var tags = new TagRegistry(classes, hierarchy); var metadataRequirements = new ClassMetadataRequirements(dependencyInfo); 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 8f911fc54..c643d9844 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 @@ -476,7 +476,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit private void fillClassFields(List fields, String className) { var classReader = classSource.get(className); - if (classReader.hasModifier(ElementModifier.INTERFACE)) { + if (classReader == null || classReader.hasModifier(ElementModifier.INTERFACE)) { fillSimpleClassFields(fields, "java.lang.Object"); } else { fillSimpleClassFields(fields, className); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java index fcc548726..4a243a90f 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationContext.java @@ -29,6 +29,7 @@ import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmTag; import org.teavm.backend.wasm.model.expression.WasmNullConstant; import org.teavm.backend.wasm.runtime.WasmGCSupport; +import org.teavm.model.ClassHierarchy; import org.teavm.model.ClassReaderSource; import org.teavm.model.MethodReference; import org.teavm.model.classes.VirtualTableProvider; @@ -42,9 +43,11 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext { private WasmGCTypeMapper typeMapper; private WasmFunctionTypes functionTypes; private ClassReaderSource classes; + private ClassHierarchy hierarchy; private BaseWasmFunctionRepository functions; private WasmGCSupertypeFunctionProvider supertypeFunctions; private WasmGCCustomGeneratorProvider customGenerators; + private WasmGCIntrinsicProvider intrinsics; private WasmFunction npeMethod; private WasmFunction aaiobeMethod; private WasmFunction cceMethod; @@ -53,20 +56,23 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext { public WasmGCGenerationContext(WasmModule module, VirtualTableProvider virtualTables, WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ClassReaderSource classes, - BaseWasmFunctionRepository functions, WasmGCSupertypeFunctionProvider supertypeFunctions, - WasmGCClassInfoProvider classInfoProvider, WasmGCStandardClasses standardClasses, - WasmGCStringProvider strings, WasmGCCustomGeneratorProvider customGenerators) { + ClassHierarchy hierarchy, BaseWasmFunctionRepository functions, + WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider, + WasmGCStandardClasses standardClasses, WasmGCStringProvider strings, + WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics) { this.module = module; this.virtualTables = virtualTables; this.typeMapper = typeMapper; this.functionTypes = functionTypes; this.classes = classes; + this.hierarchy = hierarchy; this.functions = functions; this.supertypeFunctions = supertypeFunctions; this.classInfoProvider = classInfoProvider; this.standardClasses = standardClasses; this.strings = strings; this.customGenerators = customGenerators; + this.intrinsics = intrinsics; } public WasmGCClassInfoProvider classInfoProvider() { @@ -118,6 +124,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext { return classes; } + public ClassHierarchy hierarchy() { + return hierarchy; + } + public WasmFunction npeMethod() { if (npeMethod == null) { npeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "npe", @@ -151,7 +161,15 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext { return exceptionGlobal; } + public WasmModule module() { + return module; + } + public WasmGCCustomGeneratorProvider customGenerators() { return customGenerators; } + + public WasmGCIntrinsicProvider intrinsics() { + return intrinsics; + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java index c1b94804a..8861da818 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java @@ -20,16 +20,22 @@ import org.teavm.ast.ArrayType; import org.teavm.ast.BinaryExpr; import org.teavm.ast.Expr; import org.teavm.ast.InvocationExpr; +import org.teavm.ast.InvocationType; import org.teavm.ast.QualificationExpr; import org.teavm.ast.SubscriptExpr; import org.teavm.ast.UnwrapArrayExpr; +import org.teavm.backend.wasm.BaseWasmFunctionRepository; +import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.gc.PreciseTypeInference; import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationVisitor; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider; +import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper; +import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext; import org.teavm.backend.wasm.model.WasmArray; import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmFunctionType; import org.teavm.backend.wasm.model.WasmLocal; +import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmStructure; import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.expression.WasmArrayGet; @@ -39,6 +45,7 @@ import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmCall; import org.teavm.backend.wasm.model.expression.WasmCallReference; import org.teavm.backend.wasm.model.expression.WasmCast; +import org.teavm.backend.wasm.model.expression.WasmDrop; import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmGetGlobal; import org.teavm.backend.wasm.model.expression.WasmGetLocal; @@ -55,6 +62,7 @@ import org.teavm.backend.wasm.model.expression.WasmStructNewDefault; import org.teavm.backend.wasm.model.expression.WasmStructSet; import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmUnreachable; +import org.teavm.model.ClassHierarchy; import org.teavm.model.FieldReference; import org.teavm.model.MethodReference; import org.teavm.model.TextLocation; @@ -400,6 +408,30 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { result = invocation(expr, null, false); } + @Override + protected WasmExpression invocation(InvocationExpr expr, List resultConsumer, boolean willDrop) { + if (expr.getType() == InvocationType.SPECIAL || expr.getType() == InvocationType.STATIC) { + var intrinsic = context.intrinsics().get(expr.getMethod()); + if (intrinsic != null) { + var resultExpr = intrinsic.apply(expr, intrinsicContext); + if (resultConsumer != null) { + if (willDrop) { + var drop = new WasmDrop(resultExpr); + drop.setLocation(expr.getLocation()); + resultConsumer.add(drop); + } else { + resultConsumer.add(resultExpr); + } + result = null; + return null; + } else { + return resultExpr; + } + } + } + return super.invocation(expr, resultConsumer, willDrop); + } + @Override protected WasmExpression mapFirstArgumentForCall(WasmExpression argument, WasmFunction function, MethodReference method) { @@ -480,4 +512,42 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { public void generateThrow(List target, TextLocation location) { } } + + private WasmGCIntrinsicContext intrinsicContext = new WasmGCIntrinsicContext() { + @Override + public WasmExpression generate(Expr expr) { + accept(expr); + return result; + } + + @Override + public WasmModule module() { + return context.module(); + } + + @Override + public WasmFunctionTypes functionTypes() { + return context.functionTypes(); + } + + @Override + public PreciseTypeInference types() { + return types; + } + + @Override + public BaseWasmFunctionRepository functions() { + return context.functions(); + } + + @Override + public ClassHierarchy hierarchy() { + return context.hierarchy(); + } + + @Override + public WasmGCTypeMapper typeMapper() { + return context.typeMapper(); + } + }; } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCIntrinsicProvider.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCIntrinsicProvider.java new file mode 100644 index 000000000..81fb0bb3d --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCIntrinsicProvider.java @@ -0,0 +1,23 @@ +/* + * 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.generate.gc.methods; + +import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic; +import org.teavm.model.MethodReference; + +public interface WasmGCIntrinsicProvider { + WasmGCIntrinsic get(MethodReference method); +} diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCMethodGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCMethodGenerator.java index 5d0851d04..ccf9b92f4 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCMethodGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCMethodGenerator.java @@ -67,6 +67,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { private Diagnostics diagnostics; private WasmGCTypeMapper typeMapper; private WasmGCCustomGeneratorProvider customGenerators; + private WasmGCIntrinsicProvider intrinsics; private Queue queue = new ArrayDeque<>(); private Map staticMethods = new HashMap<>(); private Map instanceMethods = new HashMap<>(); @@ -89,7 +90,8 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { NameProvider names, Diagnostics diagnostics, WasmGCMethodReturnTypes returnTypes, - WasmGCCustomGeneratorProvider customGenerators + WasmGCCustomGeneratorProvider customGenerators, + WasmGCIntrinsicProvider intrinsics ) { this.module = module; this.hierarchy = hierarchy; @@ -101,6 +103,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { this.diagnostics = diagnostics; this.returnTypes = returnTypes; this.customGenerators = customGenerators; + this.intrinsics = intrinsics; } public void setTypeMapper(WasmGCTypeMapper typeMapper) { @@ -292,12 +295,14 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { typeMapper, functionTypes, classes, + hierarchy, this, supertypeFunctions, classInfoProvider, standardClasses, strings, - customGenerators + customGenerators, + intrinsics ); } return context; @@ -324,5 +329,10 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository { public WasmFunctionTypes functionTypes() { return functionTypes; } + + @Override + public WasmGCTypeMapper typeMapper() { + return typeMapper; + } }; } diff --git a/core/src/main/java/org/teavm/backend/wasm/generators/gc/SystemDoArrayCopyGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generators/gc/SystemDoArrayCopyGenerator.java new file mode 100644 index 000000000..b6dbba46f --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/generators/gc/SystemDoArrayCopyGenerator.java @@ -0,0 +1,35 @@ +/* + * 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.generators.gc; + +import org.teavm.backend.wasm.model.WasmFunction; +import org.teavm.backend.wasm.model.WasmLocal; +import org.teavm.backend.wasm.model.WasmType; +import org.teavm.backend.wasm.model.expression.WasmUnreachable; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; + +public class SystemDoArrayCopyGenerator implements WasmGCCustomGenerator { + @Override + public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) { + function.add(new WasmLocal(context.typeMapper().mapType(ValueType.object("java.lang.Object")))); + function.add(new WasmLocal(WasmType.INT32)); + function.add(new WasmLocal(context.typeMapper().mapType(ValueType.object("java.lang.Object")))); + function.add(new WasmLocal(WasmType.INT32)); + function.add(new WasmLocal(WasmType.INT32)); + function.getBody().add(new WasmUnreachable()); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGeneratorContext.java b/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGeneratorContext.java index 802305056..0d944c79c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGeneratorContext.java +++ b/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGeneratorContext.java @@ -16,10 +16,13 @@ package org.teavm.backend.wasm.generators.gc; import org.teavm.backend.wasm.WasmFunctionTypes; +import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper; import org.teavm.backend.wasm.model.WasmModule; public interface WasmGCCustomGeneratorContext { WasmModule module(); WasmFunctionTypes functionTypes(); + + WasmGCTypeMapper typeMapper(); } diff --git a/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGenerators.java b/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGenerators.java index 917d50cc8..41c67e178 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGenerators.java +++ b/core/src/main/java/org/teavm/backend/wasm/generators/gc/WasmGCCustomGenerators.java @@ -26,6 +26,7 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider { public WasmGCCustomGenerators() { fillStringPool(); + fillSystem(); } private void fillStringPool() { @@ -35,6 +36,14 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider { ); } + private void fillSystem() { + generators.put( + new MethodReference(System.class, "doArrayCopy", Object.class, int.class, Object.class, + int.class, int.class, void.class), + new SystemDoArrayCopyGenerator() + ); + } + @Override public WasmGCCustomGenerator get(MethodReference method) { return generators.get(method); diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/SystemArrayCopyIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/SystemArrayCopyIntrinsic.java new file mode 100644 index 000000000..3da3f1ff5 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/SystemArrayCopyIntrinsic.java @@ -0,0 +1,103 @@ +/* + * 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.gc.classes.WasmGCClassInfoProvider; +import org.teavm.backend.wasm.model.WasmArray; +import org.teavm.backend.wasm.model.WasmFunction; +import org.teavm.backend.wasm.model.WasmStructure; +import org.teavm.backend.wasm.model.WasmType; +import org.teavm.backend.wasm.model.expression.WasmArrayCopy; +import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmExpression; +import org.teavm.backend.wasm.model.expression.WasmStructGet; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; + +public class SystemArrayCopyIntrinsic implements WasmGCIntrinsic { + private WasmFunction defaultFunction; + + @Override + public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) { + var result = tryGenerateSpecialCase(invocation, context); + if (result == null) { + var function = getDefaultFunction(context); + result = new WasmCall(function, context.generate(invocation.getArguments().get(0)), + context.generate(invocation.getArguments().get(1)), + context.generate(invocation.getArguments().get(2)), + context.generate(invocation.getArguments().get(3)), + context.generate(invocation.getArguments().get(4))); + } + return result; + } + + private WasmExpression tryGenerateSpecialCase(InvocationExpr invocation, WasmGCIntrinsicContext context) { + var sourceArray = invocation.getArguments().get(0); + var targetArray = invocation.getArguments().get(2); + if (sourceArray.getVariableIndex() < 0 || targetArray.getVariableIndex() < 0) { + return null; + } + + var sourceType = context.types().typeOf(sourceArray.getVariableIndex()); + if (sourceType == null || !(sourceType.valueType instanceof ValueType.Array)) { + return null; + } + var targetType = context.types().typeOf(targetArray.getVariableIndex()); + if (targetType == null || !(targetType.valueType instanceof ValueType.Array)) { + return null; + } + + var sourceItemType = ((ValueType.Array) sourceType.valueType).getItemType(); + var targetItemType = ((ValueType.Array) targetType.valueType).getItemType(); + if (sourceItemType != targetItemType + || !context.hierarchy().isSuperType(targetItemType, sourceItemType, false)) { + return null; + } + + var wasmTargetArrayType = (WasmType.CompositeReference) context.typeMapper().mapType( + ValueType.arrayOf(targetItemType)); + var wasmTargetArrayStruct = (WasmStructure) wasmTargetArrayType.composite; + var wasmTargetArrayWrapper = context.generate(invocation.getArguments().get(2)); + var wasmTargetArray = new WasmStructGet(wasmTargetArrayStruct, wasmTargetArrayWrapper, + WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET); + var wasmTargetIndex = context.generate(invocation.getArguments().get(3)); + var wasmSourceArrayType = (WasmType.CompositeReference) context.typeMapper().mapType( + ValueType.arrayOf(sourceItemType)); + var wasmSourceArrayStruct = (WasmStructure) wasmSourceArrayType.composite; + var wasmSourceArrayWrapper = context.generate(invocation.getArguments().get(0)); + var wasmSourceArray = new WasmStructGet(wasmSourceArrayStruct, wasmSourceArrayWrapper, + WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET); + var wasmSourceIndex = context.generate(invocation.getArguments().get(1)); + var wasmSize = context.generate(invocation.getArguments().get(4)); + + var wasmTargetArrayTypeRef = (WasmType.CompositeReference) wasmTargetArrayStruct.getFields() + .get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).asUnpackedType(); + var wasmSourceArrayTypeRef = (WasmType.CompositeReference) wasmSourceArrayStruct.getFields() + .get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).asUnpackedType(); + + return new WasmArrayCopy((WasmArray) wasmTargetArrayTypeRef.composite, wasmTargetArray, wasmTargetIndex, + (WasmArray) wasmSourceArrayTypeRef.composite, wasmSourceArray, wasmSourceIndex, wasmSize); + } + + private WasmFunction getDefaultFunction(WasmGCIntrinsicContext manager) { + if (defaultFunction == null) { + defaultFunction = manager.functions().forStaticMethod(new MethodReference(System.class, + "arraycopy", Object.class, int.class, Object.class, int.class, int.class, void.class)); + } + return defaultFunction; + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsic.java new file mode 100644 index 000000000..bf54dbc82 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsic.java @@ -0,0 +1,23 @@ +/* + * 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.model.expression.WasmExpression; + +public interface WasmGCIntrinsic { + WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context); +} diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsicContext.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsicContext.java new file mode 100644 index 000000000..56c066eb5 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsicContext.java @@ -0,0 +1,41 @@ +/* + * 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.Expr; +import org.teavm.backend.wasm.BaseWasmFunctionRepository; +import org.teavm.backend.wasm.WasmFunctionTypes; +import org.teavm.backend.wasm.gc.PreciseTypeInference; +import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper; +import org.teavm.backend.wasm.model.WasmModule; +import org.teavm.backend.wasm.model.expression.WasmExpression; +import org.teavm.model.ClassHierarchy; + +public interface WasmGCIntrinsicContext { + WasmExpression generate(Expr expr); + + WasmModule module(); + + WasmFunctionTypes functionTypes(); + + PreciseTypeInference types(); + + BaseWasmFunctionRepository functions(); + + ClassHierarchy hierarchy(); + + WasmGCTypeMapper typeMapper(); +} 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 new file mode 100644 index 000000000..f0f30e435 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/WasmGCIntrinsics.java @@ -0,0 +1,39 @@ +/* + * 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.HashMap; +import java.util.Map; +import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider; +import org.teavm.model.MethodReference; + +public class WasmGCIntrinsics implements WasmGCIntrinsicProvider { + private Map intrinsics = new HashMap<>(); + + public WasmGCIntrinsics() { + fillSystem(); + } + + private void fillSystem() { + intrinsics.put(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class, + int.class, int.class, void.class), new SystemArrayCopyIntrinsic()); + } + + @Override + public WasmGCIntrinsic get(MethodReference method) { + return intrinsics.get(method); + } +} diff --git a/core/src/main/java/org/teavm/model/analysis/BaseTypeInference.java b/core/src/main/java/org/teavm/model/analysis/BaseTypeInference.java index dfc061355..4883a1171 100644 --- a/core/src/main/java/org/teavm/model/analysis/BaseTypeInference.java +++ b/core/src/main/java/org/teavm/model/analysis/BaseTypeInference.java @@ -487,24 +487,24 @@ public abstract class BaseTypeInference { @Override public void visit(InvokeInstruction insn) { if (insn.getInstance() != null) { - push(insn.getInstance(), ValueType.object(reference.getClassName())); + push(insn.getInstance(), ValueType.object(insn.getMethod().getClassName())); } for (var i = 0; i < insn.getArguments().size(); ++i) { - push(insn.getArguments().get(i), reference.parameterType(i)); + push(insn.getArguments().get(i), insn.getMethod().parameterType(i)); } } @Override public void visit(GetFieldInstruction insn) { if (insn.getInstance() != null) { - push(insn.getInstance(), ValueType.object(reference.getClassName())); + push(insn.getInstance(), ValueType.object(insn.getField().getClassName())); } } @Override public void visit(PutFieldInstruction insn) { if (insn.getInstance() != null) { - push(insn.getInstance(), ValueType.object(reference.getClassName())); + push(insn.getInstance(), ValueType.object(insn.getField().getClassName())); } push(insn.getValue(), insn.getFieldType()); } diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index e6ffab864..36e0d60d0 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -823,7 +823,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository { optimizations.add(new ClassInitElimination()); optimizations.add(new UnreachableBasicBlockElimination()); optimizations.add(new UnusedVariableElimination()); - optimizations.add(new SystemArrayCopyOptimization()); + if (target.needsSystemArrayCopyOptimization()) { + optimizations.add(new SystemArrayCopyOptimization()); + } return optimizations; } diff --git a/core/src/main/java/org/teavm/vm/TeaVMTarget.java b/core/src/main/java/org/teavm/vm/TeaVMTarget.java index d0eb5d48e..d61490ef7 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMTarget.java +++ b/core/src/main/java/org/teavm/vm/TeaVMTarget.java @@ -66,4 +66,8 @@ public interface TeaVMTarget { default Collection getInitializerMethods() { return null; } + + default boolean needsSystemArrayCopyOptimization() { + return true; + } }