wasm gc: support System.arrayCopy for special cases

This commit is contained in:
Alexey Andreev 2024-08-03 20:59:19 +02:00
parent 065aef581d
commit e61301576b
17 changed files with 405 additions and 14 deletions

View File

@ -20,6 +20,7 @@ import java.util.List;
import org.teavm.backend.wasm.gc.WasmGCDependencies; import org.teavm.backend.wasm.gc.WasmGCDependencies;
import org.teavm.backend.wasm.generate.gc.WasmGCDeclarationsGenerator; import org.teavm.backend.wasm.generate.gc.WasmGCDeclarationsGenerator;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerators; 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.model.WasmModule;
import org.teavm.backend.wasm.render.WasmBinaryRenderer; import org.teavm.backend.wasm.render.WasmBinaryRenderer;
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector; 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 { public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException {
var module = new WasmModule(); var module = new WasmModule();
var customGenerators = new WasmGCCustomGenerators(); var customGenerators = new WasmGCCustomGenerators();
var intrinsics = new WasmGCIntrinsics();
var declarationsGenerator = new WasmGCDeclarationsGenerator( var declarationsGenerator = new WasmGCDeclarationsGenerator(
module, module,
classes, classes,
@ -115,7 +117,8 @@ public class WasmGCTarget implements TeaVMTarget {
controller.getClassInitializerInfo(), controller.getClassInitializerInfo(),
controller.getDependencyInfo(), controller.getDependencyInfo(),
controller.getDiagnostics(), controller.getDiagnostics(),
customGenerators customGenerators,
intrinsics
); );
declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger()); declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger());
var moduleGenerator = new WasmGCModuleGenerator(declarationsGenerator); var moduleGenerator = new WasmGCModuleGenerator(declarationsGenerator);
@ -156,4 +159,9 @@ public class WasmGCTarget implements TeaVMTarget {
output.write(data); output.write(data);
} }
} }
@Override
public boolean needsSystemArrayCopyOptimization() {
return false;
}
} }

View File

@ -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.WasmGCSupertypeFunctionProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper; 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.WasmGCCustomGeneratorProvider;
import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider;
import org.teavm.backend.wasm.generate.gc.methods.WasmGCMethodGenerator; import org.teavm.backend.wasm.generate.gc.methods.WasmGCMethodGenerator;
import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmModule;
@ -55,7 +56,8 @@ public class WasmGCDeclarationsGenerator {
ClassInitializerInfo classInitializerInfo, ClassInitializerInfo classInitializerInfo,
DependencyInfo dependencyInfo, DependencyInfo dependencyInfo,
Diagnostics diagnostics, Diagnostics diagnostics,
WasmGCCustomGeneratorProvider customGenerators WasmGCCustomGeneratorProvider customGenerators,
WasmGCIntrinsicProvider intrinsics
) { ) {
this.module = module; this.module = module;
hierarchy = new ClassHierarchy(classes); hierarchy = new ClassHierarchy(classes);
@ -73,7 +75,8 @@ public class WasmGCDeclarationsGenerator {
names, names,
diagnostics, diagnostics,
returnTypes, returnTypes,
customGenerators customGenerators,
intrinsics
); );
var tags = new TagRegistry(classes, hierarchy); var tags = new TagRegistry(classes, hierarchy);
var metadataRequirements = new ClassMetadataRequirements(dependencyInfo); var metadataRequirements = new ClassMetadataRequirements(dependencyInfo);

View File

@ -476,7 +476,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private void fillClassFields(List<WasmStorageType> fields, String className) { private void fillClassFields(List<WasmStorageType> fields, String className) {
var classReader = classSource.get(className); var classReader = classSource.get(className);
if (classReader.hasModifier(ElementModifier.INTERFACE)) { if (classReader == null || classReader.hasModifier(ElementModifier.INTERFACE)) {
fillSimpleClassFields(fields, "java.lang.Object"); fillSimpleClassFields(fields, "java.lang.Object");
} else { } else {
fillSimpleClassFields(fields, className); fillSimpleClassFields(fields, className);

View File

@ -29,6 +29,7 @@ import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmTag; import org.teavm.backend.wasm.model.WasmTag;
import org.teavm.backend.wasm.model.expression.WasmNullConstant; import org.teavm.backend.wasm.model.expression.WasmNullConstant;
import org.teavm.backend.wasm.runtime.WasmGCSupport; import org.teavm.backend.wasm.runtime.WasmGCSupport;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.classes.VirtualTableProvider; import org.teavm.model.classes.VirtualTableProvider;
@ -42,9 +43,11 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
private WasmGCTypeMapper typeMapper; private WasmGCTypeMapper typeMapper;
private WasmFunctionTypes functionTypes; private WasmFunctionTypes functionTypes;
private ClassReaderSource classes; private ClassReaderSource classes;
private ClassHierarchy hierarchy;
private BaseWasmFunctionRepository functions; private BaseWasmFunctionRepository functions;
private WasmGCSupertypeFunctionProvider supertypeFunctions; private WasmGCSupertypeFunctionProvider supertypeFunctions;
private WasmGCCustomGeneratorProvider customGenerators; private WasmGCCustomGeneratorProvider customGenerators;
private WasmGCIntrinsicProvider intrinsics;
private WasmFunction npeMethod; private WasmFunction npeMethod;
private WasmFunction aaiobeMethod; private WasmFunction aaiobeMethod;
private WasmFunction cceMethod; private WasmFunction cceMethod;
@ -53,20 +56,23 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
public WasmGCGenerationContext(WasmModule module, VirtualTableProvider virtualTables, public WasmGCGenerationContext(WasmModule module, VirtualTableProvider virtualTables,
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ClassReaderSource classes, WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ClassReaderSource classes,
BaseWasmFunctionRepository functions, WasmGCSupertypeFunctionProvider supertypeFunctions, ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
WasmGCClassInfoProvider classInfoProvider, WasmGCStandardClasses standardClasses, WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
WasmGCStringProvider strings, WasmGCCustomGeneratorProvider customGenerators) { WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics) {
this.module = module; this.module = module;
this.virtualTables = virtualTables; this.virtualTables = virtualTables;
this.typeMapper = typeMapper; this.typeMapper = typeMapper;
this.functionTypes = functionTypes; this.functionTypes = functionTypes;
this.classes = classes; this.classes = classes;
this.hierarchy = hierarchy;
this.functions = functions; this.functions = functions;
this.supertypeFunctions = supertypeFunctions; this.supertypeFunctions = supertypeFunctions;
this.classInfoProvider = classInfoProvider; this.classInfoProvider = classInfoProvider;
this.standardClasses = standardClasses; this.standardClasses = standardClasses;
this.strings = strings; this.strings = strings;
this.customGenerators = customGenerators; this.customGenerators = customGenerators;
this.intrinsics = intrinsics;
} }
public WasmGCClassInfoProvider classInfoProvider() { public WasmGCClassInfoProvider classInfoProvider() {
@ -118,6 +124,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
return classes; return classes;
} }
public ClassHierarchy hierarchy() {
return hierarchy;
}
public WasmFunction npeMethod() { public WasmFunction npeMethod() {
if (npeMethod == null) { if (npeMethod == null) {
npeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "npe", npeMethod = functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "npe",
@ -151,7 +161,15 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
return exceptionGlobal; return exceptionGlobal;
} }
public WasmModule module() {
return module;
}
public WasmGCCustomGeneratorProvider customGenerators() { public WasmGCCustomGeneratorProvider customGenerators() {
return customGenerators; return customGenerators;
} }
public WasmGCIntrinsicProvider intrinsics() {
return intrinsics;
}
} }

View File

@ -20,16 +20,22 @@ import org.teavm.ast.ArrayType;
import org.teavm.ast.BinaryExpr; import org.teavm.ast.BinaryExpr;
import org.teavm.ast.Expr; import org.teavm.ast.Expr;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.ast.InvocationType;
import org.teavm.ast.QualificationExpr; import org.teavm.ast.QualificationExpr;
import org.teavm.ast.SubscriptExpr; import org.teavm.ast.SubscriptExpr;
import org.teavm.ast.UnwrapArrayExpr; 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.gc.PreciseTypeInference;
import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationVisitor; 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.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.WasmArray;
import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmFunctionType; import org.teavm.backend.wasm.model.WasmFunctionType;
import org.teavm.backend.wasm.model.WasmLocal; 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.WasmStructure;
import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmArrayGet; 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.WasmCall;
import org.teavm.backend.wasm.model.expression.WasmCallReference; import org.teavm.backend.wasm.model.expression.WasmCallReference;
import org.teavm.backend.wasm.model.expression.WasmCast; 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.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmGetGlobal; import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
import org.teavm.backend.wasm.model.expression.WasmGetLocal; 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.WasmStructSet;
import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmThrow;
import org.teavm.backend.wasm.model.expression.WasmUnreachable; import org.teavm.backend.wasm.model.expression.WasmUnreachable;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.TextLocation; import org.teavm.model.TextLocation;
@ -400,6 +408,30 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
result = invocation(expr, null, false); result = invocation(expr, null, false);
} }
@Override
protected WasmExpression invocation(InvocationExpr expr, List<WasmExpression> 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 @Override
protected WasmExpression mapFirstArgumentForCall(WasmExpression argument, WasmFunction function, protected WasmExpression mapFirstArgumentForCall(WasmExpression argument, WasmFunction function,
MethodReference method) { MethodReference method) {
@ -480,4 +512,42 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
public void generateThrow(List<WasmExpression> target, TextLocation location) { public void generateThrow(List<WasmExpression> 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();
}
};
} }

View File

@ -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);
}

View File

@ -67,6 +67,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
private Diagnostics diagnostics; private Diagnostics diagnostics;
private WasmGCTypeMapper typeMapper; private WasmGCTypeMapper typeMapper;
private WasmGCCustomGeneratorProvider customGenerators; private WasmGCCustomGeneratorProvider customGenerators;
private WasmGCIntrinsicProvider intrinsics;
private Queue<Runnable> queue = new ArrayDeque<>(); private Queue<Runnable> queue = new ArrayDeque<>();
private Map<MethodReference, WasmFunction> staticMethods = new HashMap<>(); private Map<MethodReference, WasmFunction> staticMethods = new HashMap<>();
private Map<MethodReference, WasmFunction> instanceMethods = new HashMap<>(); private Map<MethodReference, WasmFunction> instanceMethods = new HashMap<>();
@ -89,7 +90,8 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
NameProvider names, NameProvider names,
Diagnostics diagnostics, Diagnostics diagnostics,
WasmGCMethodReturnTypes returnTypes, WasmGCMethodReturnTypes returnTypes,
WasmGCCustomGeneratorProvider customGenerators WasmGCCustomGeneratorProvider customGenerators,
WasmGCIntrinsicProvider intrinsics
) { ) {
this.module = module; this.module = module;
this.hierarchy = hierarchy; this.hierarchy = hierarchy;
@ -101,6 +103,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
this.diagnostics = diagnostics; this.diagnostics = diagnostics;
this.returnTypes = returnTypes; this.returnTypes = returnTypes;
this.customGenerators = customGenerators; this.customGenerators = customGenerators;
this.intrinsics = intrinsics;
} }
public void setTypeMapper(WasmGCTypeMapper typeMapper) { public void setTypeMapper(WasmGCTypeMapper typeMapper) {
@ -292,12 +295,14 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
typeMapper, typeMapper,
functionTypes, functionTypes,
classes, classes,
hierarchy,
this, this,
supertypeFunctions, supertypeFunctions,
classInfoProvider, classInfoProvider,
standardClasses, standardClasses,
strings, strings,
customGenerators customGenerators,
intrinsics
); );
} }
return context; return context;
@ -324,5 +329,10 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
public WasmFunctionTypes functionTypes() { public WasmFunctionTypes functionTypes() {
return functionTypes; return functionTypes;
} }
@Override
public WasmGCTypeMapper typeMapper() {
return typeMapper;
}
}; };
} }

View File

@ -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());
}
}

View File

@ -16,10 +16,13 @@
package org.teavm.backend.wasm.generators.gc; package org.teavm.backend.wasm.generators.gc;
import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmModule;
public interface WasmGCCustomGeneratorContext { public interface WasmGCCustomGeneratorContext {
WasmModule module(); WasmModule module();
WasmFunctionTypes functionTypes(); WasmFunctionTypes functionTypes();
WasmGCTypeMapper typeMapper();
} }

View File

@ -26,6 +26,7 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
public WasmGCCustomGenerators() { public WasmGCCustomGenerators() {
fillStringPool(); fillStringPool();
fillSystem();
} }
private void fillStringPool() { 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 @Override
public WasmGCCustomGenerator get(MethodReference method) { public WasmGCCustomGenerator get(MethodReference method) {
return generators.get(method); return generators.get(method);

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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<MethodReference, WasmGCIntrinsic> 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);
}
}

View File

@ -487,24 +487,24 @@ public abstract class BaseTypeInference<T> {
@Override @Override
public void visit(InvokeInstruction insn) { public void visit(InvokeInstruction insn) {
if (insn.getInstance() != null) { 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) { 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 @Override
public void visit(GetFieldInstruction insn) { public void visit(GetFieldInstruction insn) {
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
push(insn.getInstance(), ValueType.object(reference.getClassName())); push(insn.getInstance(), ValueType.object(insn.getField().getClassName()));
} }
} }
@Override @Override
public void visit(PutFieldInstruction insn) { public void visit(PutFieldInstruction insn) {
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
push(insn.getInstance(), ValueType.object(reference.getClassName())); push(insn.getInstance(), ValueType.object(insn.getField().getClassName()));
} }
push(insn.getValue(), insn.getFieldType()); push(insn.getValue(), insn.getFieldType());
} }

View File

@ -823,7 +823,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
optimizations.add(new ClassInitElimination()); optimizations.add(new ClassInitElimination());
optimizations.add(new UnreachableBasicBlockElimination()); optimizations.add(new UnreachableBasicBlockElimination());
optimizations.add(new UnusedVariableElimination()); optimizations.add(new UnusedVariableElimination());
if (target.needsSystemArrayCopyOptimization()) {
optimizations.add(new SystemArrayCopyOptimization()); optimizations.add(new SystemArrayCopyOptimization());
}
return optimizations; return optimizations;
} }

View File

@ -66,4 +66,8 @@ public interface TeaVMTarget {
default Collection<? extends MethodReference> getInitializerMethods() { default Collection<? extends MethodReference> getInitializerMethods() {
return null; return null;
} }
default boolean needsSystemArrayCopyOptimization() {
return true;
}
} }