wasm gc: implement ServiceLoader

This commit is contained in:
Alexey Andreev 2024-09-17 15:19:59 +02:00
parent 36f7ec36f3
commit 55ac5d0321
14 changed files with 365 additions and 18 deletions

View File

@ -22,6 +22,7 @@ import java.util.ServiceLoader;
import org.teavm.backend.c.TeaVMCHost; import org.teavm.backend.c.TeaVMCHost;
import org.teavm.backend.javascript.TeaVMJavaScriptHost; import org.teavm.backend.javascript.TeaVMJavaScriptHost;
import org.teavm.backend.wasm.TeaVMWasmHost; import org.teavm.backend.wasm.TeaVMWasmHost;
import org.teavm.backend.wasm.gc.TeaVMWasmGCHost;
import org.teavm.classlib.ReflectionSupplier; import org.teavm.classlib.ReflectionSupplier;
import org.teavm.classlib.impl.currency.CountriesGenerator; import org.teavm.classlib.impl.currency.CountriesGenerator;
import org.teavm.classlib.impl.currency.CurrenciesGenerator; import org.teavm.classlib.impl.currency.CurrenciesGenerator;
@ -94,6 +95,11 @@ public class JCLPlugin implements TeaVMPlugin {
if (wasmHost != null) { if (wasmHost != null) {
wasmHost.add(new ServiceLoaderWasmSupport()); wasmHost.add(new ServiceLoaderWasmSupport());
} }
var wasmGCHost = host.getExtension(TeaVMWasmGCHost.class);
if (wasmGCHost != null) {
wasmGCHost.addGeneratorFactory(new ServiceLoaderWasmGCSupport());
}
} }
if (!isBootstrap()) { if (!isBootstrap()) {

View File

@ -0,0 +1,179 @@
/*
* Copyright 2021 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.classlib.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ServiceLoader;
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorContext;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorFactory;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorFactoryContext;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmGlobal;
import org.teavm.backend.wasm.model.WasmLocal;
import org.teavm.backend.wasm.model.WasmType;
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.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmFunctionReference;
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
import org.teavm.backend.wasm.model.expression.WasmNullBranch;
import org.teavm.backend.wasm.model.expression.WasmNullCondition;
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
import org.teavm.backend.wasm.model.expression.WasmReturn;
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
import org.teavm.backend.wasm.model.expression.WasmStructGet;
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
import org.teavm.backend.wasm.model.expression.WasmStructSet;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class ServiceLoaderWasmGCSupport implements WasmGCCustomGeneratorFactory {
static final MethodDescriptor INIT_METHOD = new MethodDescriptor("<init>", ValueType.VOID);
@Override
public WasmGCCustomGenerator createGenerator(MethodReference methodRef,
WasmGCCustomGeneratorFactoryContext context) {
if (methodRef.getClassName().equals(ServiceLoader.class.getName())
&& methodRef.getName().equals("loadServices")) {
return new ServiceLoaderIntrinsic(context.services().getService(ServiceLoaderInformation.class));
}
return null;
}
static class ServiceLoaderIntrinsic implements WasmGCCustomGenerator {
private ServiceLoaderInformation information;
ServiceLoaderIntrinsic(ServiceLoaderInformation information) {
this.information = information;
}
@Override
public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) {
var initializer = generateInitializer(context);
var emptyInitializer = generateEmptyInitializer(context);
var arrayType = (WasmType.Reference) context.typeMapper().mapType(ValueType.parse(Object[].class));
var servicesFunctionType = context.functionTypes().of(arrayType);
var classLocal = new WasmLocal(context.typeMapper().mapType(ValueType.parse(Class.class)));
function.add(classLocal);
var classStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
var initializerGlobalName = context.names().topLevel("teavm@initializeServicesRef");
var global = new WasmGlobal(initializerGlobalName, initializer.getType().getReference(),
new WasmFunctionReference(initializer));
context.module().globals.add(global);
initializer.getBody().add(0, new WasmSetGlobal(global, new WasmFunctionReference(emptyInitializer)));
function.getBody().add(new WasmCallReference(new WasmGetGlobal(global), initializer.getType()));
var block = new WasmBlock(false);
var servicesFunctionRef = new WasmStructGet(classStruct, new WasmGetLocal(classLocal),
context.classInfoProvider().getServicesOffset());
var nullCheckedRef = new WasmNullBranch(WasmNullCondition.NULL, servicesFunctionRef, block);
var getServices = new WasmCallReference(nullCheckedRef, servicesFunctionType);
block.getBody().add(new WasmReturn(getServices));
function.getBody().add(block);
function.getBody().add(new WasmNullConstant(arrayType));
}
private WasmFunction generateInitializer(WasmGCCustomGeneratorContext context) {
var function = new WasmFunction(context.functionTypes().of(null));
function.setReferenced(true);
function.setName(context.names().topLevel("teavm@initializeServices"));
context.module().functions.add(function);
var serviceTypes = information.serviceTypes();
var classStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
var fieldIndex = context.classInfoProvider().getServicesOffset();
for (var serviceType : serviceTypes) {
var implementations = information.serviceImplementations(serviceType);
var providerFunction = generateServiceProvider(context, serviceType, implementations);
var classInfo = context.classInfoProvider().getClassInfo(serviceType);
var classRef = new WasmGetGlobal(classInfo.getPointer());
var providerRef = new WasmFunctionReference(providerFunction);
function.getBody().add(new WasmStructSet(classStruct, classRef, fieldIndex, providerRef));
}
return function;
}
private WasmFunction generateServiceProvider(WasmGCCustomGeneratorContext context,
String interfaceName, Collection<? extends String> implementations) {
var functionType = context.functionTypes().of(context.typeMapper().mapType(
ValueType.parse(Object[].class)));
var function = new WasmFunction(functionType);
function.setName(context.names().topLevel(context.names().suggestForClass(interfaceName) + "@services"));
function.setReferenced(true);
context.module().functions.add(function);
var tempVars = new TemporaryVariablePool(function);
var util = new WasmGCGenerationUtil(context.classInfoProvider(), tempVars);
var block = new WasmBlock(false);
block.setType(context.typeMapper().mapType(ValueType.parse(Object[].class)));
util.allocateArrayWithElements(ValueType.parse(Object.class), () -> {
var items = new ArrayList<WasmExpression>();
for (var implementationName : implementations) {
items.add(instantiateService(context, function, implementationName));
}
return items;
}, null, null, function.getBody());
return function;
}
private WasmExpression instantiateService(WasmGCCustomGeneratorContext context,
WasmFunction function, String implementationName) {
var implementationInfo = context.classInfoProvider().getClassInfo(implementationName);
var block = new WasmBlock(false);
block.setType(context.typeMapper().mapType(ValueType.parse(Object.class)));
var tmpVar = new WasmLocal(implementationInfo.getType());
function.add(tmpVar);
var structNew = new WasmSetLocal(tmpVar, new WasmStructNewDefault(
implementationInfo.getStructure()));
block.getBody().add(structNew);
var initClassField = new WasmStructSet(implementationInfo.getStructure(), new WasmGetLocal(tmpVar),
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET, new WasmGetGlobal(implementationInfo.getPointer()));
block.getBody().add(initClassField);
var constructor = context.functions().forInstanceMethod(
new MethodReference(implementationName, INIT_METHOD));
block.getBody().add(new WasmCall(constructor, new WasmGetLocal(tmpVar)));
block.getBody().add(new WasmGetLocal(tmpVar));
return block;
}
private WasmFunction generateEmptyInitializer(WasmGCCustomGeneratorContext context) {
var function = new WasmFunction(context.functionTypes().of(null));
function.setReferenced(true);
function.setName(context.names().topLevel("teavm@emptyServicesInitializer"));
context.module().functions.add(function);
function.getBody().add(new WasmReturn());
return function;
}
}
}

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.classlib.java.util; package org.teavm.classlib.java.util;
import org.teavm.classlib.PlatformDetector;
import org.teavm.classlib.java.lang.*; import org.teavm.classlib.java.lang.*;
import org.teavm.platform.PlatformClass; import org.teavm.platform.PlatformClass;
@ -45,7 +46,9 @@ public final class TServiceLoader<S> extends TObject implements TIterable<S> {
} }
public static <S> TServiceLoader<S> load(TClass<S> service) { public static <S> TServiceLoader<S> load(TClass<S> service) {
return new TServiceLoader<>(doLoadServices(service.getPlatformClass())); return new TServiceLoader<>(PlatformDetector.isWebAssemblyGC()
? doLoadServices(service)
: doLoadServices(service.getPlatformClass()));
} }
public static <S> TServiceLoader<S> load(TClass<S> service, @SuppressWarnings("unused") TClassLoader loader) { public static <S> TServiceLoader<S> load(TClass<S> service, @SuppressWarnings("unused") TClassLoader loader) {
@ -66,6 +69,16 @@ public final class TServiceLoader<S> extends TObject implements TIterable<S> {
private static native Object[] loadServices(PlatformClass cls); private static native Object[] loadServices(PlatformClass cls);
private static Object[] doLoadServices(TClass<?> cls) {
Object[] result = loadServices(cls);
if (result == null) {
result = new Object[0];
}
return result;
}
private static native Object[] loadServices(TClass<?> cls);
public void reload() { public void reload() {
// Do nothing, services are bound at build time // Do nothing, services are bound at build time
} }

View File

@ -25,6 +25,8 @@ import org.teavm.backend.wasm.gc.TeaVMWasmGCHost;
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.generate.gc.classes.WasmGCCustomTypeMapperFactory; import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapperFactory;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorFactory;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerators; import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerators;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic; import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory; import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory;
@ -62,6 +64,8 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
private List<WasmGCIntrinsicFactory> intrinsicFactories = new ArrayList<>(); private List<WasmGCIntrinsicFactory> intrinsicFactories = new ArrayList<>();
private Map<MethodReference, WasmGCIntrinsic> customIntrinsics = new HashMap<>(); private Map<MethodReference, WasmGCIntrinsic> customIntrinsics = new HashMap<>();
private List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories = new ArrayList<>(); private List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories = new ArrayList<>();
private Map<MethodReference, WasmGCCustomGenerator> customCustomGenerators = new HashMap<>();
private List<WasmGCCustomGeneratorFactory> customGeneratorFactories = new ArrayList<>();
public void setObfuscated(boolean obfuscated) { public void setObfuscated(boolean obfuscated) {
this.obfuscated = obfuscated; this.obfuscated = obfuscated;
@ -81,6 +85,16 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
customIntrinsics.put(method, intrinsic); customIntrinsics.put(method, intrinsic);
} }
@Override
public void addGeneratorFactory(WasmGCCustomGeneratorFactory factory) {
customGeneratorFactories.add(factory);
}
@Override
public void addGenerator(MethodReference method, WasmGCCustomGenerator generator) {
customCustomGenerators.put(method, generator);
}
@Override @Override
public void addCustomTypeMapperFactory(WasmGCCustomTypeMapperFactory customTypeMapperFactory) { public void addCustomTypeMapperFactory(WasmGCCustomTypeMapperFactory customTypeMapperFactory) {
customTypeMapperFactories.add(customTypeMapperFactory); customTypeMapperFactories.add(customTypeMapperFactory);
@ -151,8 +165,9 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
@Override @Override
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(classes, controller.getServices(),
var intrinsics = new WasmGCIntrinsics(classes, intrinsicFactories, customIntrinsics); customGeneratorFactories, customCustomGenerators);
var intrinsics = new WasmGCIntrinsics(classes, controller.getServices(), intrinsicFactories, customIntrinsics);
var declarationsGenerator = new WasmGCDeclarationsGenerator( var declarationsGenerator = new WasmGCDeclarationsGenerator(
module, module,
classes, classes,

View File

@ -16,6 +16,8 @@
package org.teavm.backend.wasm.gc; package org.teavm.backend.wasm.gc;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapperFactory; import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapperFactory;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorFactory;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic; import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory; import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
@ -26,5 +28,9 @@ public interface TeaVMWasmGCHost extends TeaVMHostExtension {
void addIntrinsic(MethodReference method, WasmGCIntrinsic intrinsic); void addIntrinsic(MethodReference method, WasmGCIntrinsic intrinsic);
void addGeneratorFactory(WasmGCCustomGeneratorFactory factory);
void addGenerator(MethodReference method, WasmGCCustomGenerator generator);
void addCustomTypeMapperFactory(WasmGCCustomTypeMapperFactory customTypeMapperFactory); void addCustomTypeMapperFactory(WasmGCCustomTypeMapperFactory customTypeMapperFactory);
} }

View File

@ -83,6 +83,7 @@ public class WasmGCDeclarationsGenerator {
module, module,
classes, classes,
hierarchy, hierarchy,
dependencyInfo,
functionTypes, functionTypes,
tags, tags,
metadataRequirements, metadataRequirements,

View File

@ -24,6 +24,7 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.ServiceLoader;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.BaseWasmFunctionRepository;
@ -75,6 +76,7 @@ import org.teavm.backend.wasm.model.expression.WasmStructNew;
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault; 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.runtime.WasmGCSupport; import org.teavm.backend.wasm.runtime.WasmGCSupport;
import org.teavm.dependency.DependencyInfo;
import org.teavm.model.ClassHierarchy; import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
@ -143,6 +145,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private int arrayLengthOffset = -1; private int arrayLengthOffset = -1;
private int arrayGetOffset = -1; private int arrayGetOffset = -1;
private int cloneOffset = -1; private int cloneOffset = -1;
private int servicesOffset = -1;
private WasmStructure arrayVirtualTableStruct; private WasmStructure arrayVirtualTableStruct;
private WasmFunction arrayGetObjectFunction; private WasmFunction arrayGetObjectFunction;
private WasmFunction arrayLengthObjectFunction; private WasmFunction arrayLengthObjectFunction;
@ -150,9 +153,10 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private WasmFunctionType arrayLengthType; private WasmFunctionType arrayLengthType;
private List<WasmStructure> nonInitializedStructures = new ArrayList<>(); private List<WasmStructure> nonInitializedStructures = new ArrayList<>();
private WasmArray objectArrayType; private WasmArray objectArrayType;
private boolean hasLoadServices;
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource, public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
ClassHierarchy hierarchy, ClassHierarchy hierarchy, DependencyInfo dependencyInfo,
WasmFunctionTypes functionTypes, TagRegistry tagRegistry, WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables, ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables,
BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names, BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names,
@ -177,6 +181,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
typeMapper.setCustomTypeMappers(customTypeMapperFactories.stream() typeMapper.setCustomTypeMappers(customTypeMapperFactories.stream()
.map(factory -> factory.createTypeMapper(customTypeMapperFactoryContext)) .map(factory -> factory.createTypeMapper(customTypeMapperFactoryContext))
.collect(Collectors.toList())); .collect(Collectors.toList()));
var loadServicesMethod = dependencyInfo.getMethod(new MethodReference(ServiceLoader.class, "loadServices",
Class.class, Object[].class));
if (loadServicesMethod != null && loadServicesMethod.isUsed()) {
hasLoadServices = true;
}
} }
private WasmGCCustomTypeMapperFactoryContext customTypeMapperFactoryContext() { private WasmGCCustomTypeMapperFactoryContext customTypeMapperFactoryContext() {
@ -443,6 +453,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
return cloneOffset; return cloneOffset;
} }
@Override
public int getServicesOffset() {
standardClasses.classClass().getStructure().init();
return servicesOffset;
}
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) { private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
classInfo.initializer = target -> { classInfo.initializer = target -> {
int kind; int kind;
@ -1152,6 +1168,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
cloneOffset = fields.size(); cloneOffset = fields.size();
fields.add(createClassField(functionTypes.of(standardClasses.objectClass().getType(), fields.add(createClassField(functionTypes.of(standardClasses.objectClass().getType(),
standardClasses.objectClass().getType()).getReference().asStorage(), "clone")); standardClasses.objectClass().getType()).getReference().asStorage(), "clone"));
if (hasLoadServices) {
servicesOffset = fields.size();
var serviceFunctionType = functionTypes.of(getClassInfo(ValueType.parse(Object[].class)).getType());
fields.add(createClassField(serviceFunctionType.getReference().asStorage(), "services"));
}
if (metadataRequirements.hasEnumConstants()) { if (metadataRequirements.hasEnumConstants()) {
enumConstantsFunctionOffset = fields.size(); enumConstantsFunctionOffset = fields.size();
var enumArrayType = getClassInfo(ValueType.arrayOf(ValueType.object("java.lang.Enum"))).getType(); var enumArrayType = getClassInfo(ValueType.arrayOf(ValueType.object("java.lang.Enum"))).getType();

View File

@ -67,6 +67,8 @@ public interface WasmGCClassInfoProvider {
int getCloneOffset(); int getCloneOffset();
int getServicesOffset();
default WasmGCClassInfo getClassInfo(String name) { default WasmGCClassInfo getClassInfo(String name) {
return getClassInfo(ValueType.object(name)); return getClassInfo(ValueType.object(name));
} }

View File

@ -28,6 +28,7 @@ import org.teavm.ast.decompilation.Decompiler;
import org.teavm.backend.wasm.BaseWasmFunctionRepository; import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes; 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.gc.PreciseValueType;
import org.teavm.backend.wasm.gc.WasmGCVariableCategoryProvider; import org.teavm.backend.wasm.gc.WasmGCVariableCategoryProvider;
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider; import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
@ -269,6 +270,9 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
var localVar = ast.getVariables().get(i); var localVar = ast.getVariables().get(i);
var representative = method.getProgram().variableAt(variableRepresentatives[i]); var representative = method.getProgram().variableAt(variableRepresentatives[i]);
var inferredType = typeInference.typeOf(representative); var inferredType = typeInference.typeOf(representative);
if (inferredType == null) {
inferredType = new PreciseValueType(ValueType.object("java.lang.Object"), false);
}
var type = !inferredType.isArrayUnwrap var type = !inferredType.isArrayUnwrap
? typeMapper.mapType(inferredType.valueType) ? typeMapper.mapType(inferredType.valueType)
: classInfoProvider.getClassInfo(inferredType.valueType).getArray().getReference(); : classInfoProvider.getClassInfo(inferredType.valueType).getArray().getReference();

View File

@ -0,0 +1,22 @@
/*
* 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.model.MethodReference;
public interface WasmGCCustomGeneratorFactory {
WasmGCCustomGenerator createGenerator(MethodReference methodRef, WasmGCCustomGeneratorFactoryContext context);
}

View File

@ -0,0 +1,25 @@
/*
* Copyright 2024 konsoletyper.
*
* 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.common.ServiceRepository;
import org.teavm.model.ClassReaderSource;
public interface WasmGCCustomGeneratorFactoryContext {
ClassReaderSource classes();
ServiceRepository services();
}

View File

@ -17,36 +17,46 @@ package org.teavm.backend.wasm.generators.gc;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider; import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
import org.teavm.backend.wasm.runtime.WasmGCSupport; import org.teavm.backend.wasm.runtime.WasmGCSupport;
import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider { public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
private Map<MethodReference, WasmGCCustomGenerator> generators = new HashMap<>(); private List<WasmGCCustomGeneratorFactory> factories;
private Map<MethodReference, Container> generators = new HashMap<>();
private ClassReaderSource classes;
private ServiceRepository services;
public WasmGCCustomGenerators() { public WasmGCCustomGenerators(ClassReaderSource classes, ServiceRepository services,
List<WasmGCCustomGeneratorFactory> factories,
Map<MethodReference, WasmGCCustomGenerator> generators) {
this.factories = List.copyOf(factories);
this.classes = classes;
this.services = services;
fillClass(); fillClass();
fillStringPool(); fillStringPool();
fillSystem(); fillSystem();
fillArray(); fillArray();
for (var entry : generators.entrySet()) {
add(entry.getKey(), entry.getValue());
}
} }
private void fillClass() { private void fillClass() {
var classGenerators = new ClassGenerators(); var classGenerators = new ClassGenerators();
generators.put(new MethodReference(Class.class, "isAssignableFrom", Class.class, boolean.class), add(new MethodReference(Class.class, "isAssignableFrom", Class.class, boolean.class), classGenerators);
classGenerators);
} }
private void fillStringPool() { private void fillStringPool() {
generators.put( add(new MethodReference(WasmGCSupport.class, "nextByte", byte.class), new WasmGCStringPoolGenerator());
new MethodReference(WasmGCSupport.class, "nextByte", byte.class),
new WasmGCStringPoolGenerator()
);
} }
private void fillSystem() { private void fillSystem() {
generators.put( add(
new MethodReference(System.class, "doArrayCopy", Object.class, int.class, Object.class, new MethodReference(System.class, "doArrayCopy", Object.class, int.class, Object.class,
int.class, int.class, void.class), int.class, int.class, void.class),
new SystemDoArrayCopyGenerator() new SystemDoArrayCopyGenerator()
@ -55,12 +65,44 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
private void fillArray() { private void fillArray() {
var arrayGenerator = new ArrayGenerator(); var arrayGenerator = new ArrayGenerator();
generators.put(new MethodReference(Array.class, "newInstanceImpl", Class.class, int.class, Object.class), add(new MethodReference(Array.class, "newInstanceImpl", Class.class, int.class, Object.class), arrayGenerator);
arrayGenerator);
} }
@Override @Override
public WasmGCCustomGenerator get(MethodReference method) { public WasmGCCustomGenerator get(MethodReference method) {
return generators.get(method); var result = generators.get(method);
if (result == null) {
WasmGCCustomGenerator generator = null;
for (var factory : factories) {
generator = factory.createGenerator(method, factoryContext);
} }
result = new Container(generator);
generators.put(method, result);
}
return result.generator;
}
private void add(MethodReference method, WasmGCCustomGenerator generator) {
generators.put(method, new Container(generator));
}
private static class Container {
final WasmGCCustomGenerator generator;
Container(WasmGCCustomGenerator generator) {
this.generator = generator;
}
}
private WasmGCCustomGeneratorFactoryContext factoryContext = new WasmGCCustomGeneratorFactoryContext() {
@Override
public ClassReaderSource classes() {
return classes;
}
@Override
public ServiceRepository services() {
return services;
}
};
} }

View File

@ -15,8 +15,11 @@
*/ */
package org.teavm.backend.wasm.intrinsics.gc; package org.teavm.backend.wasm.intrinsics.gc;
import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
public interface WasmGCIntrinsicFactoryContext { public interface WasmGCIntrinsicFactoryContext {
ClassReaderSource classes(); ClassReaderSource classes();
ServiceRepository services();
} }

View File

@ -22,6 +22,7 @@ import java.util.Map;
import org.teavm.backend.wasm.WasmRuntime; import org.teavm.backend.wasm.WasmRuntime;
import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider; import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider;
import org.teavm.backend.wasm.model.expression.WasmIntType; import org.teavm.backend.wasm.model.expression.WasmIntType;
import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
@ -30,10 +31,12 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
private Map<MethodReference, IntrinsicContainer> intrinsics = new HashMap<>(); private Map<MethodReference, IntrinsicContainer> intrinsics = new HashMap<>();
private List<WasmGCIntrinsicFactory> factories; private List<WasmGCIntrinsicFactory> factories;
private ClassReaderSource classes; private ClassReaderSource classes;
private ServiceRepository services;
public WasmGCIntrinsics(ClassReaderSource classes, List<WasmGCIntrinsicFactory> factories, public WasmGCIntrinsics(ClassReaderSource classes, ServiceRepository services,
Map<MethodReference, WasmGCIntrinsic> customIntrinsics) { List<WasmGCIntrinsicFactory> factories, Map<MethodReference, WasmGCIntrinsic> customIntrinsics) {
this.classes = classes; this.classes = classes;
this.services = services;
this.factories = List.copyOf(factories); this.factories = List.copyOf(factories);
factories = List.copyOf(factories); factories = List.copyOf(factories);
fillWasmRuntime(); fillWasmRuntime();
@ -179,5 +182,10 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
public ClassReaderSource classes() { public ClassReaderSource classes() {
return classes; return classes;
} }
@Override
public ServiceRepository services() {
return services;
}
}; };
} }