wasm gc: implement resources

This commit is contained in:
Alexey Andreev 2024-09-05 21:15:28 +02:00
parent 29dec0962b
commit fea62af09a
49 changed files with 1541 additions and 108 deletions

View File

@ -16,10 +16,17 @@
package org.teavm.backend.wasm; package org.teavm.backend.wasm;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
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.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.WasmGCIntrinsicFactory;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsics; 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;
@ -33,6 +40,7 @@ import org.teavm.interop.Platforms;
import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ListableClassHolderSource; import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.MethodReader; import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.transformation.BoundCheckInsertion; import org.teavm.model.transformation.BoundCheckInsertion;
import org.teavm.model.transformation.NullCheckFilter; import org.teavm.model.transformation.NullCheckFilter;
@ -43,16 +51,34 @@ import org.teavm.vm.TeaVMTarget;
import org.teavm.vm.TeaVMTargetController; import org.teavm.vm.TeaVMTargetController;
import org.teavm.vm.spi.TeaVMHostExtension; import org.teavm.vm.spi.TeaVMHostExtension;
public class WasmGCTarget implements TeaVMTarget { public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
private TeaVMTargetController controller; private TeaVMTargetController controller;
private NullCheckInsertion nullCheckInsertion; private NullCheckInsertion nullCheckInsertion;
private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion(); private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion();
private boolean obfuscated; private boolean obfuscated;
private List<WasmGCIntrinsicFactory> intrinsicFactories = new ArrayList<>();
private Map<MethodReference, WasmGCIntrinsic> customIntrinsics = new HashMap<>();
private List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories = new ArrayList<>();
public void setObfuscated(boolean obfuscated) { public void setObfuscated(boolean obfuscated) {
this.obfuscated = obfuscated; this.obfuscated = obfuscated;
} }
@Override
public void addIntrinsicFactory(WasmGCIntrinsicFactory intrinsicFactory) {
intrinsicFactories.add(intrinsicFactory);
}
@Override
public void addIntrinsic(MethodReference method, WasmGCIntrinsic intrinsic) {
customIntrinsics.put(method, intrinsic);
}
@Override
public void addCustomTypeMapperFactory(WasmGCCustomTypeMapperFactory customTypeMapperFactory) {
customTypeMapperFactories.add(customTypeMapperFactory);
}
@Override @Override
public void setController(TeaVMTargetController controller) { public void setController(TeaVMTargetController controller) {
this.controller = controller; this.controller = controller;
@ -85,7 +111,7 @@ public class WasmGCTarget implements TeaVMTarget {
@Override @Override
public List<TeaVMHostExtension> getHostExtensions() { public List<TeaVMHostExtension> getHostExtensions() {
return List.of(); return List.of(this);
} }
@Override @Override
@ -114,15 +140,17 @@ 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 intrinsics = new WasmGCIntrinsics(classes, intrinsicFactories, customIntrinsics);
var declarationsGenerator = new WasmGCDeclarationsGenerator( var declarationsGenerator = new WasmGCDeclarationsGenerator(
module, module,
classes, classes,
controller.getClassLoader(),
controller.getClassInitializerInfo(), controller.getClassInitializerInfo(),
controller.getDependencyInfo(), controller.getDependencyInfo(),
controller.getDiagnostics(), controller.getDiagnostics(),
customGenerators, customGenerators,
intrinsics, intrinsics,
customTypeMapperFactories,
controller::isVirtual controller::isVirtual
); );
declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger()); declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger());

View File

@ -75,6 +75,9 @@ public abstract class BaseDisassemblyListener {
case ANY: case ANY:
writer.write("anyref"); writer.write("anyref");
return; return;
case EQ:
writer.write("eqref");
return;
case FUNC: case FUNC:
writer.write("funcref"); writer.write("funcref");
return; return;
@ -99,6 +102,9 @@ public abstract class BaseDisassemblyListener {
case ANY: case ANY:
writer.write("any"); writer.write("any");
return; return;
case EQ:
writer.write("eq");
return;
case FUNC: case FUNC:
writer.write("func"); writer.write("func");
return; return;

View File

@ -815,6 +815,13 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
writer.eol(); writer.eol();
} }
@Override
public void arrayNewFixed(int typeIndex, int size) {
writer.address().write("array.new_fixed ");
writeTypeRef(typeIndex);
writer.write(" ").write(Integer.toString(size)).eol();
}
@Override @Override
public void arrayGet(WasmSignedType signedType, int typeIndex) { public void arrayGet(WasmSignedType signedType, int typeIndex) {
writer.address(); writer.address();

View File

@ -0,0 +1,30 @@
/*
* 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.gc;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapperFactory;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory;
import org.teavm.model.MethodReference;
import org.teavm.vm.spi.TeaVMHostExtension;
public interface TeaVMWasmGCHost extends TeaVMHostExtension {
void addIntrinsicFactory(WasmGCIntrinsicFactory intrinsicFactory);
void addIntrinsic(MethodReference method, WasmGCIntrinsic intrinsic);
void addCustomTypeMapperFactory(WasmGCCustomTypeMapperFactory customTypeMapperFactory);
}

View File

@ -22,6 +22,7 @@ import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTableProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassGenerator; import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassGenerator;
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.WasmGCCustomTypeMapperFactory;
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;
@ -49,11 +50,13 @@ public class WasmGCDeclarationsGenerator {
public WasmGCDeclarationsGenerator( public WasmGCDeclarationsGenerator(
WasmModule module, WasmModule module,
ListableClassHolderSource classes, ListableClassHolderSource classes,
ClassLoader classLoader,
ClassInitializerInfo classInitializerInfo, ClassInitializerInfo classInitializerInfo,
DependencyInfo dependencyInfo, DependencyInfo dependencyInfo,
Diagnostics diagnostics, Diagnostics diagnostics,
WasmGCCustomGeneratorProvider customGenerators, WasmGCCustomGeneratorProvider customGenerators,
WasmGCIntrinsicProvider intrinsics, WasmGCIntrinsicProvider intrinsics,
List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories,
Predicate<MethodReference> isVirtual Predicate<MethodReference> isVirtual
) { ) {
this.module = module; this.module = module;
@ -65,6 +68,7 @@ public class WasmGCDeclarationsGenerator {
module, module,
hierarchy, hierarchy,
classes, classes,
classLoader,
virtualTables, virtualTables,
classInitializerInfo, classInitializerInfo,
functionTypes, functionTypes,
@ -84,7 +88,8 @@ public class WasmGCDeclarationsGenerator {
virtualTables, virtualTables,
methodGenerator, methodGenerator,
names, names,
classInitializerInfo classInitializerInfo,
customTypeMapperFactories
); );
methodGenerator.setClassInfoProvider(classGenerator); methodGenerator.setClassInfoProvider(classGenerator);
methodGenerator.setStrings(classGenerator.strings); methodGenerator.setStrings(classGenerator.strings);

View File

@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors;
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.vtable.WasmGCVirtualTable; import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTable;
@ -137,7 +138,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
WasmFunctionTypes functionTypes, TagRegistry tagRegistry, WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables, ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables,
BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names, BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names,
ClassInitializerInfo classInitializerInfo) { ClassInitializerInfo classInitializerInfo,
List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories) {
this.module = module; this.module = module;
this.classSource = classSource; this.classSource = classSource;
this.functionTypes = functionTypes; this.functionTypes = functionTypes;
@ -152,6 +154,39 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes); supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes);
newArrayGenerator = new WasmGCNewArrayFunctionGenerator(module, functionTypes, this, names); newArrayGenerator = new WasmGCNewArrayFunctionGenerator(module, functionTypes, this, names);
typeMapper = new WasmGCTypeMapper(classSource, this, functionTypes, module); typeMapper = new WasmGCTypeMapper(classSource, this, functionTypes, module);
var customTypeMapperFactoryContext = customTypeMapperFactoryContext();
typeMapper.setCustomTypeMappers(customTypeMapperFactories.stream()
.map(factory -> factory.createTypeMapper(customTypeMapperFactoryContext))
.collect(Collectors.toList()));
}
private WasmGCCustomTypeMapperFactoryContext customTypeMapperFactoryContext() {
return new WasmGCCustomTypeMapperFactoryContext() {
@Override
public ClassReaderSource classes() {
return classSource;
}
@Override
public WasmModule module() {
return module;
}
@Override
public WasmGCClassInfoProvider classInfoProvider() {
return WasmGCClassGenerator.this;
}
@Override
public WasmGCNameProvider names() {
return names;
}
@Override
public WasmGCTypeMapper typeMapper() {
return typeMapper;
}
};
} }
public WasmGCSupertypeFunctionProvider getSupertypeProvider() { public WasmGCSupertypeFunctionProvider getSupertypeProvider() {

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.generate.gc.classes;
import org.teavm.backend.wasm.model.WasmType;
public interface WasmGCCustomTypeMapper {
WasmType map(String className);
}

View File

@ -0,0 +1,20 @@
/*
* 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.classes;
public interface WasmGCCustomTypeMapperFactory {
WasmGCCustomTypeMapper createTypeMapper(WasmGCCustomTypeMapperFactoryContext context);
}

View File

@ -0,0 +1,32 @@
/*
* 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.classes;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.model.ClassReaderSource;
public interface WasmGCCustomTypeMapperFactoryContext {
ClassReaderSource classes();
WasmModule module();
WasmGCClassInfoProvider classInfoProvider();
WasmGCTypeMapper typeMapper();
WasmGCNameProvider names();
}

View File

@ -15,7 +15,9 @@
*/ */
package org.teavm.backend.wasm.generate.gc.classes; package org.teavm.backend.wasm.generate.gc.classes;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.teavm.backend.wasm.WasmFunctionTypes; import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.model.WasmFunctionType; import org.teavm.backend.wasm.model.WasmFunctionType;
import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmModule;
@ -31,6 +33,8 @@ public class WasmGCTypeMapper {
private WasmGCClassInfoProvider classInfoProvider; private WasmGCClassInfoProvider classInfoProvider;
private WasmFunctionTypes functionTypes; private WasmFunctionTypes functionTypes;
private WasmModule module; private WasmModule module;
private List<WasmGCCustomTypeMapper> customTypeMappers;
private Map<String, WasmType> typeCache = new HashMap<>();
WasmGCTypeMapper(ClassReaderSource classes, WasmGCClassInfoProvider classInfoProvider, WasmGCTypeMapper(ClassReaderSource classes, WasmGCClassInfoProvider classInfoProvider,
WasmFunctionTypes functionTypes, WasmModule module) { WasmFunctionTypes functionTypes, WasmModule module) {
@ -40,6 +44,10 @@ public class WasmGCTypeMapper {
this.module = module; this.module = module;
} }
void setCustomTypeMappers(List<WasmGCCustomTypeMapper> customTypeMappers) {
this.customTypeMappers = List.copyOf(customTypeMappers);
}
public WasmStorageType mapStorageType(ValueType type) { public WasmStorageType mapStorageType(ValueType type) {
if (type instanceof ValueType.Primitive) { if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) { switch (((ValueType.Primitive) type).getKind()) {
@ -61,7 +69,7 @@ public class WasmGCTypeMapper {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} else { } else {
return classInfoProvider.getClassInfo(type).getType().asStorage(); return mapType(type).asStorage();
} }
} }
@ -86,12 +94,7 @@ public class WasmGCTypeMapper {
} else if (type instanceof ValueType.Void) { } else if (type instanceof ValueType.Void) {
return null; return null;
} else if (type instanceof ValueType.Object) { } else if (type instanceof ValueType.Object) {
var className = ((ValueType.Object) type).getClassName(); return mapClassType(((ValueType.Object) type).getClassName());
var cls = classes.get(className);
if (cls == null) {
className = "java.lang.Object";
}
return classInfoProvider.getClassInfo(className).getType();
} else if (type instanceof ValueType.Array) { } else if (type instanceof ValueType.Array) {
var degree = 0; var degree = 0;
while (type instanceof ValueType.Array) { while (type instanceof ValueType.Array) {
@ -114,6 +117,27 @@ public class WasmGCTypeMapper {
} }
} }
private WasmType mapClassType(String className) {
var result = typeCache.get(className);
if (result == null) {
for (var customMapper : customTypeMappers) {
result = customMapper.map(className);
if (result != null) {
break;
}
}
if (result == null) {
var cls = classes.get(className);
if (cls == null) {
className = "java.lang.Object";
}
result = classInfoProvider.getClassInfo(className).getType();
typeCache.put(className, result);
}
}
return result;
}
public WasmFunctionType getFunctionType(WasmType receiverType, MethodDescriptor methodDesc, boolean fresh) { public WasmFunctionType getFunctionType(WasmType receiverType, MethodDescriptor methodDesc, boolean fresh) {
var returnType = mapType(methodDesc.getResultType()); var returnType = mapType(methodDesc.getResultType());
var javaParamTypes = methodDesc.getParameterTypes(); var javaParamTypes = methodDesc.getParameterTypes();

View File

@ -52,6 +52,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
private WasmGCTypeMapper typeMapper; private WasmGCTypeMapper typeMapper;
private WasmFunctionTypes functionTypes; private WasmFunctionTypes functionTypes;
private ListableClassReaderSource classes; private ListableClassReaderSource classes;
private ClassLoader classLoader;
private ClassHierarchy hierarchy; private ClassHierarchy hierarchy;
private BaseWasmFunctionRepository functions; private BaseWasmFunctionRepository functions;
private WasmGCSupertypeFunctionProvider supertypeFunctions; private WasmGCSupertypeFunctionProvider supertypeFunctions;
@ -67,7 +68,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
public WasmGCGenerationContext(WasmModule module, WasmGCVirtualTableProvider virtualTables, public WasmGCGenerationContext(WasmModule module, WasmGCVirtualTableProvider virtualTables,
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ListableClassReaderSource classes, WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ListableClassReaderSource classes,
ClassHierarchy hierarchy, BaseWasmFunctionRepository functions, ClassLoader classLoader, ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider, WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings, WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics, WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics,
@ -77,6 +78,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
this.typeMapper = typeMapper; this.typeMapper = typeMapper;
this.functionTypes = functionTypes; this.functionTypes = functionTypes;
this.classes = classes; this.classes = classes;
this.classLoader = classLoader;
this.hierarchy = hierarchy; this.hierarchy = hierarchy;
this.functions = functions; this.functions = functions;
this.supertypeFunctions = supertypeFunctions; this.supertypeFunctions = supertypeFunctions;
@ -92,6 +94,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
return classInfoProvider; return classInfoProvider;
} }
public WasmGCNameProvider names() {
return names;
}
public WasmGCStandardClasses standardClasses() { public WasmGCStandardClasses standardClasses() {
return standardClasses; return standardClasses;
} }
@ -137,6 +143,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
return classes; return classes;
} }
public ClassLoader classLoader() {
return classLoader;
}
public ClassHierarchy hierarchy() { public ClassHierarchy hierarchy() {
return hierarchy; return hierarchy;
} }

View File

@ -30,8 +30,10 @@ import org.teavm.backend.wasm.gc.PreciseTypeInference;
import org.teavm.backend.wasm.generate.ExpressionCache; import org.teavm.backend.wasm.generate.ExpressionCache;
import org.teavm.backend.wasm.generate.TemporaryVariablePool; import org.teavm.backend.wasm.generate.TemporaryVariablePool;
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.WasmGCNameProvider;
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.generate.gc.classes.WasmGCTypeMapper;
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext; 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;
@ -585,6 +587,11 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
return result; return result;
} }
@Override
public ClassLoader classLoader() {
return context.classLoader();
}
@Override @Override
public WasmModule module() { public WasmModule module() {
return context.module(); return context.module();
@ -629,5 +636,15 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
public ExpressionCache exprCache() { public ExpressionCache exprCache() {
return exprCache; return exprCache;
} }
@Override
public WasmGCNameProvider names() {
return context.names();
}
@Override
public WasmGCStringProvider strings() {
return context.strings();
}
}; };
} }

View File

@ -60,6 +60,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
private WasmModule module; private WasmModule module;
private ClassHierarchy hierarchy; private ClassHierarchy hierarchy;
private ListableClassHolderSource classes; private ListableClassHolderSource classes;
private ClassLoader classLoader;
private WasmGCVirtualTableProvider virtualTables; private WasmGCVirtualTableProvider virtualTables;
private ClassInitializerInfo classInitInfo; private ClassInitializerInfo classInitInfo;
private WasmFunctionTypes functionTypes; private WasmFunctionTypes functionTypes;
@ -84,6 +85,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
WasmModule module, WasmModule module,
ClassHierarchy hierarchy, ClassHierarchy hierarchy,
ListableClassHolderSource classes, ListableClassHolderSource classes,
ClassLoader classLoader,
WasmGCVirtualTableProvider virtualTables, WasmGCVirtualTableProvider virtualTables,
ClassInitializerInfo classInitInfo, ClassInitializerInfo classInitInfo,
WasmFunctionTypes functionTypes, WasmFunctionTypes functionTypes,
@ -95,6 +97,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
this.module = module; this.module = module;
this.hierarchy = hierarchy; this.hierarchy = hierarchy;
this.classes = classes; this.classes = classes;
this.classLoader = classLoader;
this.virtualTables = virtualTables; this.virtualTables = virtualTables;
this.classInitInfo = classInitInfo; this.classInitInfo = classInitInfo;
this.functionTypes = functionTypes; this.functionTypes = functionTypes;
@ -310,6 +313,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
typeMapper, typeMapper,
functionTypes, functionTypes,
classes, classes,
classLoader,
hierarchy, hierarchy,
this, this,
supertypeFunctions, supertypeFunctions,

View File

@ -21,8 +21,10 @@ 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.ExpressionCache; import org.teavm.backend.wasm.generate.ExpressionCache;
import org.teavm.backend.wasm.generate.TemporaryVariablePool; import org.teavm.backend.wasm.generate.TemporaryVariablePool;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
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.generate.gc.classes.WasmGCTypeMapper;
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.model.ClassHierarchy; import org.teavm.model.ClassHierarchy;
@ -47,4 +49,10 @@ public interface WasmGCIntrinsicContext {
TemporaryVariablePool tempVars(); TemporaryVariablePool tempVars();
ExpressionCache exprCache(); ExpressionCache exprCache();
WasmGCNameProvider names();
WasmGCStringProvider strings();
ClassLoader classLoader();
} }

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.intrinsics.gc;
import org.teavm.model.MethodReference;
public interface WasmGCIntrinsicFactory {
WasmGCIntrinsic createIntrinsic(MethodReference methodRef, WasmGCIntrinsicFactoryContext context);
}

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.intrinsics.gc;
import org.teavm.model.ClassReaderSource;
public interface WasmGCIntrinsicFactoryContext {
ClassReaderSource classes();
}

View File

@ -22,13 +22,20 @@ 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.model.ClassReaderSource;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
public class WasmGCIntrinsics implements WasmGCIntrinsicProvider { public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
private Map<MethodReference, WasmGCIntrinsic> intrinsics = new HashMap<>(); private Map<MethodReference, IntrinsicContainer> intrinsics = new HashMap<>();
private List<WasmGCIntrinsicFactory> factories;
private ClassReaderSource classes;
public WasmGCIntrinsics() { public WasmGCIntrinsics(ClassReaderSource classes, List<WasmGCIntrinsicFactory> factories,
Map<MethodReference, WasmGCIntrinsic> customIntrinsics) {
this.classes = classes;
this.factories = List.copyOf(factories);
factories = List.copyOf(factories);
fillWasmRuntime(); fillWasmRuntime();
fillObject(); fillObject();
fillClass(); fillClass();
@ -37,49 +44,50 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
fillFloat(); fillFloat();
fillDouble(); fillDouble();
fillArray(); fillArray();
for (var entry : customIntrinsics.entrySet()) {
add(entry.getKey(), entry.getValue());
}
} }
private void fillWasmRuntime() { private void fillWasmRuntime() {
var intrinsic = new WasmRuntimeIntrinsic(); var intrinsic = new WasmRuntimeIntrinsic();
for (var cls : List.of(int.class, long.class, float.class, double.class)) { for (var cls : List.of(int.class, long.class, float.class, double.class)) {
intrinsics.put(new MethodReference(WasmRuntime.class, "lt", cls, cls, boolean.class), intrinsic); add(new MethodReference(WasmRuntime.class, "lt", cls, cls, boolean.class), intrinsic);
intrinsics.put(new MethodReference(WasmRuntime.class, "gt", cls, cls, boolean.class), intrinsic); add(new MethodReference(WasmRuntime.class, "gt", cls, cls, boolean.class), intrinsic);
} }
for (var cls : List.of(int.class, long.class)) { for (var cls : List.of(int.class, long.class)) {
intrinsics.put(new MethodReference(WasmRuntime.class, "ltu", cls, cls, boolean.class), intrinsic); add(new MethodReference(WasmRuntime.class, "ltu", cls, cls, boolean.class), intrinsic);
intrinsics.put(new MethodReference(WasmRuntime.class, "gtu", cls, cls, boolean.class), intrinsic); add(new MethodReference(WasmRuntime.class, "gtu", cls, cls, boolean.class), intrinsic);
} }
for (var cls : List.of(float.class, double.class)) { for (var cls : List.of(float.class, double.class)) {
intrinsics.put(new MethodReference(WasmRuntime.class, "min", cls, cls, cls), intrinsic); add(new MethodReference(WasmRuntime.class, "min", cls, cls, cls), intrinsic);
intrinsics.put(new MethodReference(WasmRuntime.class, "max", cls, cls, cls), intrinsic); add(new MethodReference(WasmRuntime.class, "max", cls, cls, cls), intrinsic);
} }
} }
private void fillObject() { private void fillObject() {
var objectIntrinsics = new ObjectIntrinsic(); var intrinsic = new ObjectIntrinsic();
intrinsics.put(new MethodReference(Object.class, "getClass", Class.class), objectIntrinsics); add(new MethodReference(Object.class, "getClass", Class.class), intrinsic);
intrinsics.put(new MethodReference(Object.class.getName(), "getMonitor", add(new MethodReference(Object.class.getName(), "getMonitor",
ValueType.object("java.lang.Object$Monitor")), objectIntrinsics); ValueType.object("java.lang.Object$Monitor")), intrinsic);
intrinsics.put(new MethodReference(Object.class.getName(), "setMonitor", add(new MethodReference(Object.class.getName(), "setMonitor",
ValueType.object("java.lang.Object$Monitor"), ValueType.VOID), objectIntrinsics); ValueType.object("java.lang.Object$Monitor"), ValueType.VOID), intrinsic);
intrinsics.put(new MethodReference(Object.class.getName(), "wasmGCIdentity", ValueType.INTEGER), add(new MethodReference(Object.class.getName(), "wasmGCIdentity", ValueType.INTEGER), intrinsic);
objectIntrinsics); add(new MethodReference(Object.class.getName(), "setWasmGCIdentity", ValueType.INTEGER,
intrinsics.put(new MethodReference(Object.class.getName(), "setWasmGCIdentity", ValueType.INTEGER, ValueType.VOID), intrinsic);
ValueType.VOID), objectIntrinsics);
} }
private void fillClass() { private void fillClass() {
var intrinsic = new ClassIntrinsics(); var intrinsic = new ClassIntrinsics();
intrinsics.put(new MethodReference(Class.class, "getComponentType", Class.class), intrinsic); add(new MethodReference(Class.class, "getComponentType", Class.class), intrinsic);
intrinsics.put(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic); add(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic);
intrinsics.put(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic); add(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic);
} }
private void fillSystem() { private void fillSystem() {
intrinsics.put(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class, add(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class,
int.class, int.class, void.class), new SystemArrayCopyIntrinsic()); int.class, int.class, void.class), new SystemArrayCopyIntrinsic());
intrinsics.put(new MethodReference(System.class, "currentTimeMillis", long.class), add(new MethodReference(System.class, "currentTimeMillis", long.class), new SystemIntrinsic());
new SystemIntrinsic());
} }
private void fillLongAndInteger() { private void fillLongAndInteger() {
@ -89,42 +97,70 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
private void fillIntNum(Class<?> javaClass, Class<?> wrapperClass, WasmIntType wasmType) { private void fillIntNum(Class<?> javaClass, Class<?> wrapperClass, WasmIntType wasmType) {
var intrinsic = new IntNumIntrinsic(javaClass, wasmType); var intrinsic = new IntNumIntrinsic(javaClass, wasmType);
intrinsics.put(new MethodReference(wrapperClass, "divideUnsigned", javaClass, javaClass, javaClass), add(new MethodReference(wrapperClass, "divideUnsigned", javaClass, javaClass, javaClass), intrinsic);
intrinsic); add(new MethodReference(wrapperClass, "remainderUnsigned", javaClass, javaClass, javaClass), intrinsic);
intrinsics.put(new MethodReference(wrapperClass, "remainderUnsigned", javaClass, javaClass, javaClass), add(new MethodReference(wrapperClass, "compareUnsigned", javaClass, javaClass, int.class), intrinsic);
intrinsic);
intrinsics.put(new MethodReference(wrapperClass, "compareUnsigned", javaClass, javaClass, int.class),
intrinsic);
} }
private void fillFloat() { private void fillFloat() {
var intrinsic = new FloatIntrinsic(); var intrinsic = new FloatIntrinsic();
intrinsics.put(new MethodReference(Float.class, "getNaN", float.class), intrinsic); add(new MethodReference(Float.class, "getNaN", float.class), intrinsic);
intrinsics.put(new MethodReference(Float.class, "isNaN", float.class, boolean.class), intrinsic); add(new MethodReference(Float.class, "isNaN", float.class, boolean.class), intrinsic);
intrinsics.put(new MethodReference(Float.class, "isInfinite", float.class, boolean.class), intrinsic); add(new MethodReference(Float.class, "isInfinite", float.class, boolean.class), intrinsic);
intrinsics.put(new MethodReference(Float.class, "isFinite", float.class, boolean.class), intrinsic); add(new MethodReference(Float.class, "isFinite", float.class, boolean.class), intrinsic);
intrinsics.put(new MethodReference(Float.class, "floatToRawIntBits", float.class, int.class), intrinsic); add(new MethodReference(Float.class, "floatToRawIntBits", float.class, int.class), intrinsic);
intrinsics.put(new MethodReference(Float.class, "intBitsToFloat", int.class, float.class), intrinsic); add(new MethodReference(Float.class, "intBitsToFloat", int.class, float.class), intrinsic);
} }
private void fillDouble() { private void fillDouble() {
var intrinsic = new DoubleIntrinsic(); var intrinsic = new DoubleIntrinsic();
intrinsics.put(new MethodReference(Double.class, "getNaN", double.class), intrinsic); add(new MethodReference(Double.class, "getNaN", double.class), intrinsic);
intrinsics.put(new MethodReference(Double.class, "isNaN", double.class, boolean.class), intrinsic); add(new MethodReference(Double.class, "isNaN", double.class, boolean.class), intrinsic);
intrinsics.put(new MethodReference(Double.class, "isInfinite", double.class, boolean.class), intrinsic); add(new MethodReference(Double.class, "isInfinite", double.class, boolean.class), intrinsic);
intrinsics.put(new MethodReference(Double.class, "isFinite", double.class, boolean.class), intrinsic); add(new MethodReference(Double.class, "isFinite", double.class, boolean.class), intrinsic);
intrinsics.put(new MethodReference(Double.class, "doubleToRawLongBits", double.class, long.class), intrinsic); add(new MethodReference(Double.class, "doubleToRawLongBits", double.class, long.class), intrinsic);
intrinsics.put(new MethodReference(Double.class, "longBitsToDouble", long.class, double.class), intrinsic); add(new MethodReference(Double.class, "longBitsToDouble", long.class, double.class), intrinsic);
} }
private void fillArray() { private void fillArray() {
var intrinsic = new ArrayIntrinsic(); var intrinsic = new ArrayIntrinsic();
intrinsics.put(new MethodReference(Array.class, "getLength", Object.class, int.class), intrinsic); add(new MethodReference(Array.class, "getLength", Object.class, int.class), intrinsic);
intrinsics.put(new MethodReference(Array.class, "getImpl", Object.class, int.class, Object.class), intrinsic); add(new MethodReference(Array.class, "getImpl", Object.class, int.class, Object.class), intrinsic);
}
private void add(MethodReference methodRef, WasmGCIntrinsic intrinsic) {
intrinsics.put(methodRef, new IntrinsicContainer(intrinsic));
} }
@Override @Override
public WasmGCIntrinsic get(MethodReference method) { public WasmGCIntrinsic get(MethodReference method) {
return intrinsics.get(method); var result = intrinsics.get(method);
if (result == null) {
WasmGCIntrinsic intrinsic = null;
for (var factory : factories) {
intrinsic = factory.createIntrinsic(method, factoryContext);
if (intrinsic != null) {
break;
}
}
intrinsics.put(method, new IntrinsicContainer(intrinsic));
result = new IntrinsicContainer(intrinsic);
}
return result.intrinsic;
} }
static class IntrinsicContainer {
final WasmGCIntrinsic intrinsic;
IntrinsicContainer(WasmGCIntrinsic intrinsic) {
this.intrinsic = intrinsic;
}
}
private final WasmGCIntrinsicFactoryContext factoryContext = new WasmGCIntrinsicFactoryContext() {
@Override
public ClassReaderSource classes() {
return classes;
}
};
} }

View File

@ -20,6 +20,7 @@ import java.util.function.Supplier;
public class WasmArray extends WasmCompositeType { public class WasmArray extends WasmCompositeType {
private WasmStorageType elementType; private WasmStorageType elementType;
private boolean immutable;
private Supplier<WasmStorageType> elementTypeSupplier; private Supplier<WasmStorageType> elementTypeSupplier;
public WasmArray(String name, WasmStorageType elementType) { public WasmArray(String name, WasmStorageType elementType) {
@ -40,6 +41,14 @@ public class WasmArray extends WasmCompositeType {
return elementType; return elementType;
} }
public boolean isImmutable() {
return immutable;
}
public void setImmutable(boolean immutable) {
this.immutable = immutable;
}
@Override @Override
public void acceptVisitor(WasmCompositeTypeVisitor visitor) { public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -22,6 +22,7 @@ public class WasmField {
int index; int index;
private String name; private String name;
private WasmStorageType type; private WasmStorageType type;
private boolean immutable;
public WasmField(WasmStorageType type, String name) { public WasmField(WasmStorageType type, String name) {
this(type); this(type);
@ -56,6 +57,14 @@ public class WasmField {
this.name = name; this.name = name;
} }
public boolean isImmutable() {
return immutable;
}
public void setImmutable(boolean immutable) {
this.immutable = immutable;
}
public int getIndex() { public int getIndex() {
if (structure == null) { if (structure == null) {
return -1; return -1;

View File

@ -59,6 +59,7 @@ public abstract class WasmType {
public static abstract class Reference extends WasmType { public static abstract class Reference extends WasmType {
public static final SpecialReference FUNC = SpecialReferenceKind.FUNC.asType(); public static final SpecialReference FUNC = SpecialReferenceKind.FUNC.asType();
public static final SpecialReference ANY = SpecialReferenceKind.ANY.asType(); public static final SpecialReference ANY = SpecialReferenceKind.ANY.asType();
public static final SpecialReference EQ = SpecialReferenceKind.EQ.asType();
public static final SpecialReference EXTERN = SpecialReferenceKind.EXTERN.asType(); public static final SpecialReference EXTERN = SpecialReferenceKind.EXTERN.asType();
public static final SpecialReference STRUCT = SpecialReferenceKind.STRUCT.asType(); public static final SpecialReference STRUCT = SpecialReferenceKind.STRUCT.asType();
public static final SpecialReference ARRAY = SpecialReferenceKind.ARRAY.asType(); public static final SpecialReference ARRAY = SpecialReferenceKind.ARRAY.asType();
@ -96,6 +97,7 @@ public abstract class WasmType {
public enum SpecialReferenceKind { public enum SpecialReferenceKind {
FUNC, FUNC,
ANY, ANY,
EQ,
EXTERN, EXTERN,
STRUCT, STRUCT,
ARRAY, ARRAY,

View File

@ -0,0 +1,47 @@
/*
* 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.model.expression;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.teavm.backend.wasm.model.WasmArray;
public class WasmArrayNewFixed extends WasmExpression {
private WasmArray type;
private List<WasmExpression> elements = new ArrayList<>();
public WasmArrayNewFixed(WasmArray type) {
this.type = Objects.requireNonNull(type);
}
public WasmArray getType() {
return type;
}
public void setType(WasmArray type) {
this.type = Objects.requireNonNull(type);
}
public List<WasmExpression> getElements() {
return elements;
}
@Override
public void acceptVisitor(WasmExpressionVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -283,6 +283,13 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor {
expression.getLength().acceptVisitor(this); expression.getLength().acceptVisitor(this);
} }
@Override
public void visit(WasmArrayNewFixed expression) {
for (var element : expression.getElements()) {
element.acceptVisitor(this);
}
}
@Override @Override
public void visit(WasmArrayGet expression) { public void visit(WasmArrayGet expression) {
expression.getInstance().acceptVisitor(this); expression.getInstance().acceptVisitor(this);

View File

@ -108,6 +108,8 @@ public interface WasmExpressionVisitor {
void visit(WasmArrayNewDefault expression); void visit(WasmArrayNewDefault expression);
void visit(WasmArrayNewFixed expression);
void visit(WasmArrayGet expression); void visit(WasmArrayGet expression);
void visit(WasmArraySet expression); void visit(WasmArraySet expression);

View File

@ -336,6 +336,11 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor {
expression.setLength(mapper.apply(expression.getLength())); expression.setLength(mapper.apply(expression.getLength()));
} }
@Override
public void visit(WasmArrayNewFixed expression) {
replaceExpressions(expression.getElements());
}
@Override @Override
public void visit(WasmArrayGet expression) { public void visit(WasmArrayGet expression) {
expression.getInstance().acceptVisitor(this); expression.getInstance().acceptVisitor(this);

View File

@ -156,6 +156,9 @@ public interface CodeListener {
default void arrayNewDefault(int typeIndex) { default void arrayNewDefault(int typeIndex) {
} }
default void arrayNewFixed(int typeIndex, int size) {
}
default void arrayGet(WasmSignedType signedType, int typeIndex) { default void arrayGet(WasmSignedType signedType, int typeIndex) {
} }

View File

@ -660,6 +660,9 @@ public class CodeParser extends BaseSectionParser {
case 7: case 7:
codeListener.arrayNewDefault(readLEB()); codeListener.arrayNewDefault(readLEB());
return true; return true;
case 8:
codeListener.arrayNewFixed(readLEB(), readLEB());
return true;
case 11: case 11:
codeListener.arrayGet(null, readLEB()); codeListener.arrayGet(null, readLEB());

View File

@ -92,6 +92,8 @@ public class WasmBinaryReader {
return special(WasmType.SpecialReferenceKind.EXTERN, nullable); return special(WasmType.SpecialReferenceKind.EXTERN, nullable);
case 0x6E: case 0x6E:
return special(WasmType.SpecialReferenceKind.ANY, nullable); return special(WasmType.SpecialReferenceKind.ANY, nullable);
case 0x6D:
return special(WasmType.SpecialReferenceKind.EQ, nullable);
case 0x6C: case 0x6C:
return special(WasmType.SpecialReferenceKind.I31, nullable); return special(WasmType.SpecialReferenceKind.I31, nullable);
case 0x6B: case 0x6B:

View File

@ -31,6 +31,7 @@ import org.teavm.backend.wasm.model.expression.WasmArrayCopy;
import org.teavm.backend.wasm.model.expression.WasmArrayGet; import org.teavm.backend.wasm.model.expression.WasmArrayGet;
import org.teavm.backend.wasm.model.expression.WasmArrayLength; import org.teavm.backend.wasm.model.expression.WasmArrayLength;
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault; import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
import org.teavm.backend.wasm.model.expression.WasmArrayNewFixed;
import org.teavm.backend.wasm.model.expression.WasmArraySet; import org.teavm.backend.wasm.model.expression.WasmArraySet;
import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBlock;
import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBranch;
@ -1155,6 +1156,19 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
popLocation(); popLocation();
} }
@Override
public void visit(WasmArrayNewFixed expression) {
pushLocation(expression);
for (var element : expression.getElements()) {
element.acceptVisitor(this);
}
writer.writeByte(0xfb);
writer.writeByte(8);
writer.writeLEB(module.types.indexOf(expression.getType()));
writer.writeLEB(expression.getElements().size());
popLocation();
}
@Override @Override
public void visit(WasmArrayGet expression) { public void visit(WasmArrayGet expression) {
pushLocation(expression); pushLocation(expression);

View File

@ -65,6 +65,9 @@ public class WasmBinaryWriter {
case ANY: case ANY:
writeByte(0x6e); writeByte(0x6e);
break; break;
case EQ:
writeByte(0x6d);
break;
case EXTERN: case EXTERN:
writeByte(0x6f); writeByte(0x6f);
break; break;

View File

@ -31,6 +31,7 @@ import org.teavm.backend.wasm.model.expression.WasmArrayCopy;
import org.teavm.backend.wasm.model.expression.WasmArrayGet; import org.teavm.backend.wasm.model.expression.WasmArrayGet;
import org.teavm.backend.wasm.model.expression.WasmArrayLength; import org.teavm.backend.wasm.model.expression.WasmArrayLength;
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault; import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
import org.teavm.backend.wasm.model.expression.WasmArrayNewFixed;
import org.teavm.backend.wasm.model.expression.WasmArraySet; import org.teavm.backend.wasm.model.expression.WasmArraySet;
import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBlock;
import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBranch;
@ -1203,6 +1204,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
unsupported(); unsupported();
} }
@Override
public void visit(WasmArrayNewFixed expression) {
unsupported();
}
@Override @Override
public void visit(WasmArrayGet expression) { public void visit(WasmArrayGet expression) {
unsupported(); unsupported();

View File

@ -44,7 +44,7 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
section.writeLEB(type.getFields().size()); section.writeLEB(type.getFields().size());
for (var fieldType : type.getFields()) { for (var fieldType : type.getFields()) {
writeStorageType(fieldType.getType()); writeStorageType(fieldType.getType());
section.writeLEB(0x01); // mutable section.writeLEB(fieldType.isImmutable() ? 0 : 1);
} }
} }
@ -52,7 +52,7 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
public void visit(WasmArray type) { public void visit(WasmArray type) {
section.writeByte(0x5E); section.writeByte(0x5E);
writeStorageType(type.getElementType()); writeStorageType(type.getElementType());
section.writeLEB(0x01); // mutable section.writeLEB(type.isImmutable() ? 0 : 1);
} }
@Override @Override

View File

@ -27,6 +27,7 @@ import org.teavm.backend.wasm.model.expression.WasmArrayCopy;
import org.teavm.backend.wasm.model.expression.WasmArrayGet; import org.teavm.backend.wasm.model.expression.WasmArrayGet;
import org.teavm.backend.wasm.model.expression.WasmArrayLength; import org.teavm.backend.wasm.model.expression.WasmArrayLength;
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault; import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
import org.teavm.backend.wasm.model.expression.WasmArrayNewFixed;
import org.teavm.backend.wasm.model.expression.WasmArraySet; import org.teavm.backend.wasm.model.expression.WasmArraySet;
import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBlock;
import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBranch;
@ -765,6 +766,17 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
close(); close();
} }
@Override
public void visit(WasmArrayNewFixed expression) {
open().append("array.new_fixed");
append(" ").append(typeName(expression.getType()));
append(" ").append(Integer.toString(expression.getElements().size()));
for (var element : expression.getElements()) {
line(element);
}
close();
}
@Override @Override
public void visit(WasmArrayGet expression) { public void visit(WasmArrayGet expression) {
open(); open();

View File

@ -20,6 +20,7 @@ import org.teavm.backend.wasm.model.expression.WasmArrayCopy;
import org.teavm.backend.wasm.model.expression.WasmArrayGet; import org.teavm.backend.wasm.model.expression.WasmArrayGet;
import org.teavm.backend.wasm.model.expression.WasmArrayLength; import org.teavm.backend.wasm.model.expression.WasmArrayLength;
import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault; import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault;
import org.teavm.backend.wasm.model.expression.WasmArrayNewFixed;
import org.teavm.backend.wasm.model.expression.WasmArraySet; import org.teavm.backend.wasm.model.expression.WasmArraySet;
import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBlock;
import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBranch;
@ -311,6 +312,11 @@ public class WasmTypeInference implements WasmExpressionVisitor {
result = expression.getType().getReference(); result = expression.getType().getReference();
} }
@Override
public void visit(WasmArrayNewFixed expression) {
result = expression.getType().getReference();
}
@Override @Override
public void visit(WasmArrayGet expression) { public void visit(WasmArrayGet expression) {
result = expression.getType().getElementType().asUnpackedType(); result = expression.getType().getElementType().asUnpackedType();

View File

@ -26,14 +26,14 @@ import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap; import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StaticFieldResource; import org.teavm.platform.metadata.StaticFieldResource;
class DefaultMetadataGeneratorContext implements MetadataGeneratorContext { public class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
private ClassReaderSource classSource; private ClassReaderSource classSource;
private ClassLoader classLoader; private ClassLoader classLoader;
private Properties properties; private Properties properties;
private BuildTimeResourceProxyBuilder proxyBuilder; private BuildTimeResourceProxyBuilder proxyBuilder;
private ServiceRepository services; private ServiceRepository services;
DefaultMetadataGeneratorContext(ClassReaderSource classSource, ClassLoader classLoader, public DefaultMetadataGeneratorContext(ClassReaderSource classSource, ClassLoader classLoader,
Properties properties, ServiceRepository services) { Properties properties, ServiceRepository services) {
this.classSource = classSource; this.classSource = classSource;
this.classLoader = classLoader; this.classLoader = classLoader;

View File

@ -23,8 +23,10 @@ import org.teavm.backend.c.intrinsic.Intrinsic;
import org.teavm.backend.c.intrinsic.IntrinsicContext; import org.teavm.backend.c.intrinsic.IntrinsicContext;
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.backend.wasm.intrinsics.WasmIntrinsic; import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager; import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.interop.Async; import org.teavm.interop.Async;
import org.teavm.interop.PlatformMarker; import org.teavm.interop.PlatformMarker;
@ -34,6 +36,18 @@ import org.teavm.model.MethodReference;
import org.teavm.platform.Platform; import org.teavm.platform.Platform;
import org.teavm.platform.PlatformQueue; import org.teavm.platform.PlatformQueue;
import org.teavm.platform.metadata.MetadataGenerator; import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.plugin.wasmgc.ResourceCustomTypeMapper;
import org.teavm.platform.plugin.wasmgc.ResourceDependencySupport;
import org.teavm.platform.plugin.wasmgc.ResourceInterfaceToClassTransformer;
import org.teavm.platform.plugin.wasmgc.ResourceMapEntry;
import org.teavm.platform.plugin.wasmgc.ResourceMapHelper;
import org.teavm.platform.plugin.wasmgc.WasmGCResourceArrayIntrinsic;
import org.teavm.platform.plugin.wasmgc.WasmGCResourceMapHelperIntrinsic;
import org.teavm.platform.plugin.wasmgc.WasmGCResourceMetadataIntrinsicFactory;
import org.teavm.platform.plugin.wasmgc.WasmGCResourceMethodIntrinsicFactory;
import org.teavm.vm.TeaVMPluginUtil; import org.teavm.vm.TeaVMPluginUtil;
import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin; import org.teavm.vm.spi.TeaVMPlugin;
@ -44,8 +58,8 @@ public class PlatformPlugin implements TeaVMPlugin, MetadataRegistration {
@Override @Override
public void install(TeaVMHost host) { public void install(TeaVMHost host) {
host.add(metadataTransformer);
if (host.getExtension(TeaVMJavaScriptHost.class) != null) { if (host.getExtension(TeaVMJavaScriptHost.class) != null) {
host.add(metadataTransformer);
host.add(new ResourceTransformer()); host.add(new ResourceTransformer());
host.add(new ResourceAccessorTransformer(host)); host.add(new ResourceAccessorTransformer(host));
host.add(new ResourceAccessorDependencyListener()); host.add(new ResourceAccessorDependencyListener());
@ -67,55 +81,23 @@ public class PlatformPlugin implements TeaVMPlugin, MetadataRegistration {
metadataGeneratorConsumers.add((method, constructor, generator) -> jsHost.add(method, metadataGeneratorConsumers.add((method, constructor, generator) -> jsHost.add(method,
new MetadataProviderNativeGenerator(generator, constructor))); new MetadataProviderNativeGenerator(generator, constructor)));
} else if (!isBootstrap()) {
host.add(new StringAmplifierTransformer()); host.add(new StringAmplifierTransformer());
} }
if (!isBootstrap()) { if (!isBootstrap()) {
TeaVMWasmHost wasmHost = host.getExtension(TeaVMWasmHost.class); var wasmHost = host.getExtension(TeaVMWasmHost.class);
if (wasmHost != null) { if (wasmHost != null) {
host.add(new ResourceLowLevelTransformer()); installWasm(host, wasmHost);
metadataGeneratorConsumers.add((constructor, method, generator) -> {
wasmHost.add(ctx -> new MetadataIntrinsic(ctx.getClassSource(), ctx.getClassLoader(),
ctx.getServices(), ctx.getProperties(), constructor, method, generator));
});
wasmHost.add(ctx -> new ResourceReadIntrinsic(ctx.getClassSource(), ctx.getClassLoader()));
wasmHost.add(ctx -> new WasmIntrinsic() {
@Override
public boolean isApplicable(MethodReference methodReference) {
return methodReference.getClassName().equals(StringAmplifier.class.getName());
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
return manager.generate(invocation.getArguments().get(0));
}
});
} }
TeaVMCHost cHost = host.getExtension(TeaVMCHost.class); var cHost = host.getExtension(TeaVMCHost.class);
if (cHost != null) { if (cHost != null) {
host.add(new ResourceLowLevelTransformer()); installC(host, cHost);
MetadataCIntrinsic metadataCIntrinsic = new MetadataCIntrinsic(); }
cHost.addGenerator(ctx -> {
metadataCIntrinsic.init(ctx.getClassSource(), ctx.getClassLoader(),
ctx.getServices(), ctx.getProperties());
return metadataCIntrinsic;
});
metadataGeneratorConsumers.add(metadataCIntrinsic::addGenerator);
cHost.addIntrinsic(ctx -> new ResourceReadCIntrinsic(ctx.getClassSource()));
cHost.addIntrinsic(ctx -> new Intrinsic() {
@Override
public boolean canHandle(MethodReference method) {
return method.getClassName().equals(StringAmplifier.class.getName());
}
@Override var wasmGCHost = host.getExtension(TeaVMWasmGCHost.class);
public void apply(IntrinsicContext context, InvocationExpr invocation) { if (wasmGCHost != null) {
context.emit(invocation.getArguments().get(0)); installWasmGC(host, wasmGCHost);
}
});
} }
} }
@ -131,6 +113,91 @@ public class PlatformPlugin implements TeaVMPlugin, MetadataRegistration {
host.registerService(MetadataRegistration.class, this); host.registerService(MetadataRegistration.class, this);
} }
private void installWasm(TeaVMHost host, TeaVMWasmHost wasmHost) {
host.add(metadataTransformer);
host.add(new StringAmplifierTransformer());
host.add(new ResourceLowLevelTransformer());
metadataGeneratorConsumers.add((constructor, method, generator) -> {
wasmHost.add(ctx -> new MetadataIntrinsic(ctx.getClassSource(), ctx.getClassLoader(),
ctx.getServices(), ctx.getProperties(), constructor, method, generator));
});
wasmHost.add(ctx -> new ResourceReadIntrinsic(ctx.getClassSource(), ctx.getClassLoader()));
wasmHost.add(ctx -> new WasmIntrinsic() {
@Override
public boolean isApplicable(MethodReference methodReference) {
return methodReference.getClassName().equals(StringAmplifier.class.getName());
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
return manager.generate(invocation.getArguments().get(0));
}
});
}
private void installC(TeaVMHost host, TeaVMCHost cHost) {
host.add(metadataTransformer);
host.add(new StringAmplifierTransformer());
host.add(new ResourceLowLevelTransformer());
MetadataCIntrinsic metadataCIntrinsic = new MetadataCIntrinsic();
cHost.addGenerator(ctx -> {
metadataCIntrinsic.init(ctx.getClassSource(), ctx.getClassLoader(),
ctx.getServices(), ctx.getProperties());
return metadataCIntrinsic;
});
metadataGeneratorConsumers.add(metadataCIntrinsic::addGenerator);
cHost.addIntrinsic(ctx -> new ResourceReadCIntrinsic(ctx.getClassSource()));
cHost.addIntrinsic(ctx -> new Intrinsic() {
@Override
public boolean canHandle(MethodReference method) {
return method.getClassName().equals(StringAmplifier.class.getName());
}
@Override
public void apply(IntrinsicContext context, InvocationExpr invocation) {
context.emit(invocation.getArguments().get(0));
}
});
}
private void installWasmGC(TeaVMHost host, TeaVMWasmGCHost wasmGCHost) {
WasmGCIntrinsic amplifierIntrinsic =
(invocation, context) -> context.generate(invocation.getArguments().get(0));
wasmGCHost.addIntrinsic(new MethodReference(StringAmplifier.class, "amplify", String.class, String.class),
amplifierIntrinsic);
wasmGCHost.addIntrinsic(new MethodReference(StringAmplifier.class, "amplifyArray",
String[].class, String[].class), amplifierIntrinsic);
host.add(new ResourceInterfaceToClassTransformer());
var dependencySupport = new ResourceDependencySupport();
host.add(dependencySupport);
wasmGCHost.addCustomTypeMapperFactory(context -> new ResourceCustomTypeMapper(
context.module(),
context.typeMapper(),
context.classes(),
context.names()
));
wasmGCHost.addIntrinsicFactory(new WasmGCResourceMethodIntrinsicFactory());
var metadataIntrinsicFactory = new WasmGCResourceMetadataIntrinsicFactory(host.getProperties(), host);
wasmGCHost.addIntrinsicFactory(metadataIntrinsicFactory);
var arrayIntrinsic = new WasmGCResourceArrayIntrinsic();
wasmGCHost.addIntrinsic(new MethodReference(ResourceArray.class, "size", int.class), arrayIntrinsic);
wasmGCHost.addIntrinsic(new MethodReference(ResourceArray.class, "get", int.class, Resource.class),
arrayIntrinsic);
var mapHelperIntrinsic = new WasmGCResourceMapHelperIntrinsic();
wasmGCHost.addIntrinsic(new MethodReference(ResourceMapHelper.class, "entryCount", ResourceMap.class,
int.class), mapHelperIntrinsic);
wasmGCHost.addIntrinsic(new MethodReference(ResourceMapHelper.class, "entry", ResourceMap.class, int.class,
ResourceMapEntry.class), mapHelperIntrinsic);
metadataGeneratorConsumers.add((constructor, target, generator) -> {
dependencySupport.addMetadataMethod(target);
metadataIntrinsicFactory.addGenerator(target, generator);
});
}
@Override @Override
public void register(MethodReference method, MetadataGenerator generator) { public void register(MethodReference method, MetadataGenerator generator) {
MethodReference constructor = new MethodReference(method.getClassName(), method.getName() + "$$create", MethodReference constructor = new MethodReference(method.getClassName(), method.getName() + "$$create",

View File

@ -78,11 +78,7 @@ class ResourceProgramTransformer {
private void removeCastToResource(CastInstruction cast) { private void removeCastToResource(CastInstruction cast) {
if (!cast.isWeak() && hierarchy.isSuperType(RESOURCE, cast.getTargetType(), false)) { if (!cast.isWeak() && hierarchy.isSuperType(RESOURCE, cast.getTargetType(), false)) {
AssignInstruction assign = new AssignInstruction(); cast.setWeak(true);
assign.setReceiver(cast.getReceiver());
assign.setAssignee(cast.getValue());
assign.setLocation(cast.getLocation());
cast.replace(assign);
} }
} }

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.platform.plugin.wasmgc;
@interface FieldMarker {
String value();
int index();
}

View File

@ -0,0 +1,216 @@
/*
* 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.platform.plugin.wasmgc;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
import org.teavm.backend.wasm.model.WasmArray;
import org.teavm.backend.wasm.model.WasmGlobal;
import org.teavm.backend.wasm.model.WasmStructure;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmArrayNewFixed;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmFloat32Constant;
import org.teavm.backend.wasm.model.expression.WasmFloat64Constant;
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
import org.teavm.backend.wasm.model.expression.WasmInt64Constant;
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
import org.teavm.backend.wasm.model.expression.WasmStructNew;
import org.teavm.common.HashUtils;
import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.plugin.DefaultMetadataGeneratorContext;
import org.teavm.platform.plugin.ResourceAccessorType;
import org.teavm.platform.plugin.ResourceTypeDescriptor;
import org.teavm.platform.plugin.ResourceTypeDescriptorProvider;
class MetadataIntrinsic implements WasmGCIntrinsic {
private Properties properties;
private ServiceRepository services;
private MetadataGenerator generator;
private WasmGlobal global;
MetadataIntrinsic(Properties properties, ServiceRepository services,
MetadataGenerator generator) {
this.properties = properties;
this.services = services;
this.generator = generator;
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var global = getGlobal(invocation.getMethod(), context);
return new WasmGetGlobal(global);
}
private WasmGlobal getGlobal(MethodReference method, WasmGCIntrinsicContext context) {
if (global == null) {
var genContext = new DefaultMetadataGeneratorContext(context.hierarchy().getClassSource(),
context.classLoader(), properties, services);
var metadata = generator.generateMetadata(genContext, method);
var type = context.typeMapper().mapType(method.getReturnType());
var name = context.names().topLevel(context.names().suggestForMethod(method));
var initialValue = generateMetadata(context, metadata, type);
global = new WasmGlobal(name, type, initialValue);
context.module().globals.add(global);
}
return global;
}
private WasmExpression generateMetadata(WasmGCIntrinsicContext context, Object value, WasmType expectedType) {
if (value == null) {
return new WasmNullConstant((WasmType.Reference) expectedType);
} else if (value instanceof String) {
return new WasmGetGlobal(context.strings().getStringConstant((String) value).global);
} else if (value instanceof Boolean) {
return new WasmInt32Constant((Boolean) value ? 1 : 0);
} else if (value instanceof Integer) {
return new WasmInt32Constant((Integer) value);
} else if (value instanceof Long) {
return new WasmInt64Constant((Long) value);
} else if (value instanceof Byte) {
return new WasmInt32Constant((Byte) value);
} else if (value instanceof Short) {
return new WasmInt32Constant((Short) value);
} else if (value instanceof Character) {
return new WasmInt32Constant((Character) value);
} else if (value instanceof Float) {
return new WasmFloat32Constant((Float) value);
} else if (value instanceof Double) {
return new WasmFloat64Constant((Double) value);
} else if (value instanceof ResourceArray) {
var array = (ResourceArray<?>) value;
var type = (WasmType.CompositeReference) context.typeMapper().mapType(
ValueType.object(ResourceArray.class.getName()));
var arrayType = (WasmArray) type.composite;
var result = new WasmArrayNewFixed(arrayType);
for (var i = 0; i < array.size(); ++i) {
result.getElements().add(generateMetadata(context, array.get(i),
arrayType.getElementType().asUnpackedType()));
}
return result;
} else if (value instanceof ResourceMap) {
return generateMapResource(context, (ResourceMap<?>) value);
} else if (value instanceof ResourceTypeDescriptorProvider) {
var descriptor = ((ResourceTypeDescriptorProvider) value).getDescriptor();
return generateObjectResource(context, value, descriptor);
} else {
throw new IllegalArgumentException("Don't know how to write resource: " + value);
}
}
private WasmExpression generateMapResource(WasmGCIntrinsicContext context, ResourceMap<?> map) {
var hashTable = HashUtils.createHashTable(map.keys());
var type = (WasmType.CompositeReference) context.typeMapper().mapType(
ValueType.object(ResourceMap.class.getName()));
var arrayType = (WasmArray) type.composite;
var entryType = (WasmType.CompositeReference) context.typeMapper().mapType(
ValueType.object(ResourceMapEntry.class.getName()));
var entryStruct = (WasmStructure) entryType.composite;
var expr = new WasmArrayNewFixed(arrayType);
for (var key : hashTable) {
if (key == null) {
expr.getElements().add(new WasmNullConstant(entryType));
} else {
var value = map.get(key);
var wasmValue = generateMetadata(context, value, WasmType.Reference.EQ);
var entryExpr = new WasmStructNew(entryStruct);
var keyConstant = context.strings().getStringConstant(key);
entryExpr.getInitializers().add(new WasmGetGlobal(keyConstant.global));
entryExpr.getInitializers().add(wasmValue);
expr.getElements().add(entryExpr);
}
}
return expr;
}
private WasmExpression generateObjectResource(WasmGCIntrinsicContext context, Object value,
ResourceTypeDescriptor descriptor) {
var javaItf = descriptor.getRootInterface();
var cls = context.hierarchy().getClassSource().get(javaItf.getName());
var getterMap = new HashMap<String, Method>();
for (var entry : descriptor.getMethods().entrySet()) {
if (entry.getValue().getType() == ResourceAccessorType.GETTER) {
getterMap.put(entry.getValue().getPropertyName(), entry.getKey());
}
}
var wasmType = (WasmType.CompositeReference) context.typeMapper().mapType(ValueType.object(cls.getName()));
var wasmStruct = (WasmStructure) wasmType.composite;
var expr = new WasmStructNew(wasmStruct);
for (var field : collectFields(context.hierarchy().getClassSource(), cls)) {
var getter = getterMap.get(field.name);
Object fieldValue;
try {
fieldValue = getter.invoke(value);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
expr.getInitializers().add(generateMetadata(context, fieldValue,
context.typeMapper().mapType(field.type)));
}
return expr;
}
private List<FieldDescriptor> collectFields(ClassReaderSource classes, ClassReader cls) {
var fields = new ArrayList<FieldDescriptor>();
while (cls != null) {
for (var method : cls.getMethods()) {
var annot = method.getAnnotations().get(FieldMarker.class.getName());
if (annot != null) {
fields.add(new FieldDescriptor(annot.getValue("index").getInt(),
annot.getValue("value").getString(), method.getResultType()));
}
}
cls = classes.get(cls.getParent());
if (cls.getName().equals(Resource.class.getName())) {
break;
}
}
fields.sort(Comparator.comparingInt(f -> f.index));
return fields;
}
private static class FieldDescriptor {
final int index;
final String name;
final ValueType type;
FieldDescriptor(int index, String name, ValueType type) {
this.index = index;
this.name = name;
this.type = type;
}
}
}

View File

@ -0,0 +1,121 @@
/*
* 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.platform.plugin.wasmgc;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapper;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
import org.teavm.backend.wasm.model.WasmArray;
import org.teavm.backend.wasm.model.WasmField;
import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmStructure;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ValueType;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
public class ResourceCustomTypeMapper implements WasmGCCustomTypeMapper {
private WasmModule module;
private WasmGCTypeMapper typeMapper;
private ClassReaderSource classSource;
private WasmGCNameProvider names;
private Map<String, WasmStructure> structures = new HashMap<>();
private WasmArray array;
private WasmArray mapArray;
public ResourceCustomTypeMapper(WasmModule module, WasmGCTypeMapper typeMapper, ClassReaderSource classSource,
WasmGCNameProvider names) {
this.module = module;
this.typeMapper = typeMapper;
this.classSource = classSource;
this.names = names;
}
@Override
public WasmType map(String className) {
var cls = classSource.get(className);
if (cls == null) {
return null;
}
if (cls.getAnnotations().get(ResourceMarker.class.getName()) == null) {
return null;
}
if (className.equals(Resource.class.getName())) {
return WasmType.Reference.EQ;
}
if (className.equals(ResourceArray.class.getName())) {
if (array == null) {
array = new WasmArray(names.topLevel(names.suggestForClass(className)),
WasmType.Reference.EQ.asStorage());
array.setImmutable(true);
module.types.add(array);
}
return array.getReference();
} else if (className.equals(ResourceMap.class.getName())) {
if (mapArray == null) {
mapArray = new WasmArray(names.topLevel(names.suggestForClass(className)),
typeMapper.mapStorageType(ValueType.object(ResourceMapEntry.class.getName())));
mapArray.setImmutable(true);
module.types.add(mapArray);
}
return mapArray.getReference();
} else {
return getStructure(className).getReference();
}
}
private WasmStructure getStructure(String className) {
var struct = structures.get(className);
if (struct == null) {
var name = names.topLevel(names.suggestForClass(className));
var cls = classSource.get(className);
struct = new WasmStructure(name, fields -> addFieldsFromClass(cls, fields));
module.types.add(struct);
structures.put(className, struct);
if (!cls.getParent().equals(Resource.class.getName())) {
struct.setSupertype(getStructure(cls.getParent()));
}
}
return struct;
}
private void addFieldsFromClass(ClassReader cls, List<WasmField> fields) {
if (!cls.getName().equals(Resource.class.getName())) {
var parentCls = classSource.get(cls.getParent());
if (parentCls != null) {
addFieldsFromClass(parentCls, fields);
}
}
for (var method : cls.getMethods()) {
var annot = method.getAnnotations().get(FieldMarker.class.getName());
if (annot == null) {
continue;
}
var fieldName = annot.getValue("value").getString();
var fieldType = typeMapper.mapStorageType(method.getResultType());
var field = new WasmField(fieldType, names.structureField(fieldName));
field.setImmutable(true);
fields.add(field);
}
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.platform.plugin.wasmgc;
import java.util.HashSet;
import java.util.Set;
import org.teavm.dependency.AbstractDependencyListener;
import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.MethodDependency;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class ResourceDependencySupport extends AbstractDependencyListener {
private Set<MethodReference> metadataMethods = new HashSet<>();
@Override
public void methodReached(DependencyAgent agent, MethodDependency method) {
var annot = method.getMethod().getAnnotations().get(FieldMarker.class.getName());
if (annot != null) {
var type = method.getMethod().getResultType();
if (type instanceof ValueType.Object) {
method.getResult().propagate(agent.getType(((ValueType.Object) type).getClassName()));
}
}
if (metadataMethods.contains(method.getMethod().getReference())) {
var resultType = method.getMethod().getResultType();
if (resultType instanceof ValueType.Object) {
method.getResult().propagate(agent.getType(((ValueType.Object) resultType).getClassName()));
}
}
}
public void addMetadataMethod(MethodReference method) {
metadataMethods.add(method);
}
}

View File

@ -0,0 +1,153 @@
/*
* 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.platform.plugin.wasmgc;
import org.teavm.model.AnnotationHolder;
import org.teavm.model.AnnotationValue;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassHolderTransformerContext;
import org.teavm.model.ElementModifier;
import org.teavm.model.Program;
import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceMap;
public class ResourceInterfaceToClassTransformer implements ClassHolderTransformer {
private static final String RESOURCE_CLASS = Resource.class.getName();
@Override
public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) {
if (context.getHierarchy().isSuperType(RESOURCE_CLASS, cls.getName(), false)
&& cls.hasModifier(ElementModifier.INTERFACE)) {
cls.getModifiers().remove(ElementModifier.INTERFACE);
cls.getModifiers().add(ElementModifier.ABSTRACT);
int index = 0;
if (!cls.getInterfaces().isEmpty()) {
var parent = cls.getInterfaces().iterator().next();
cls.getInterfaces().clear();
cls.setParent(parent);
var parentCls = context.getHierarchy().getClassSource().get(parent);
if (parentCls != null) {
var resourceAnnot = parentCls.getAnnotations().get(ResourceMarker.class.getName());
if (resourceAnnot != null) {
index = resourceAnnot.getValue("fieldCount").getInt();
}
}
}
for (var method : cls.getMethods()) {
method.getModifiers().remove(ElementModifier.ABSTRACT);
method.getModifiers().add(ElementModifier.NATIVE);
if (method.getName().startsWith("get") && method.getName().length() > 3
&& Character.isUpperCase(method.getName().charAt(3))
&& method.getResultType() != ValueType.VOID) {
var fieldName = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4);
var annot = new AnnotationHolder(FieldMarker.class.getName());
annot.getValues().put("value", new AnnotationValue(fieldName));
annot.getValues().put("index", new AnnotationValue(index++));
method.getAnnotations().add(annot);
} else if (method.getName().startsWith("is") && method.getName().length() > 2
&& Character.isUpperCase(method.getName().charAt(2))
&& method.getResultType() == ValueType.BOOLEAN) {
var fieldName = Character.toLowerCase(method.getName().charAt(2)) + method.getName().substring(3);
var annot = new AnnotationHolder(FieldMarker.class.getName());
annot.getValues().put("value", new AnnotationValue(fieldName));
annot.getValues().put("index", new AnnotationValue(index++));
method.getAnnotations().add(annot);
}
}
if (cls.getName().equals(ResourceMap.class.getName())) {
transformResourceMapMethods(cls, context.getHierarchy());
}
var resourceAnnot = new AnnotationHolder(ResourceMarker.class.getName());
resourceAnnot.getValues().put("fieldCount", new AnnotationValue(index));
cls.getAnnotations().add(resourceAnnot);
} else {
for (var method : cls.getMethods()) {
if (method.getProgram() != null) {
transformResourceUsages(method.getProgram(), context);
}
}
}
}
private void transformResourceMapMethods(ClassHolder cls, ClassHierarchy hierarchy) {
for (var method : cls.getMethods()) {
switch (method.getName()) {
case "has": {
method.getModifiers().remove(ElementModifier.NATIVE);
var pe = ProgramEmitter.create(method, hierarchy);
pe.invoke(ResourceMapHelper.class, "has", boolean.class, pe.var(0, ResourceMap.class),
pe.var(1, String.class)).returnValue();
break;
}
case "get": {
method.getModifiers().remove(ElementModifier.NATIVE);
var pe = ProgramEmitter.create(method, hierarchy);
pe.invoke(ResourceMapHelper.class, "get", Resource.class, pe.var(0, ResourceMap.class),
pe.var(1, String.class)).returnValue();
break;
}
case "keys": {
method.getModifiers().remove(ElementModifier.NATIVE);
var pe = ProgramEmitter.create(method, hierarchy);
pe.invoke(ResourceMapHelper.class, "keys", String[].class, pe.var(0, ResourceMap.class))
.returnValue();
break;
}
}
}
}
private void transformResourceUsages(Program program, ClassHolderTransformerContext context) {
for (var block : program.getBasicBlocks()) {
for (var instruction : block) {
if (instruction instanceof CastInstruction) {
var cast = (CastInstruction) instruction;
if (cast.isWeak()) {
continue;
}
if (!(cast.getTargetType() instanceof ValueType.Object)) {
continue;
}
var className = ((ValueType.Object) cast.getTargetType()).getClassName();
if (context.getHierarchy().isSuperType(RESOURCE_CLASS, className, false)) {
cast.setWeak(true);
}
} else if (instruction instanceof InvokeInstruction) {
var invoke = (InvokeInstruction) instruction;
if (invoke.getInstance() == null || invoke.getType() == InvocationType.SPECIAL) {
continue;
}
if (!context.getHierarchy().isSuperType(RESOURCE_CLASS, invoke.getMethod().getClassName(),
false)) {
continue;
}
invoke.setType(InvocationType.SPECIAL);
}
}
}
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.platform.plugin.wasmgc;
import org.teavm.platform.metadata.Resource;
public interface ResourceMapEntry extends Resource {
String getKey();
Resource getValue();
}

View File

@ -0,0 +1,78 @@
/*
* 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.platform.plugin.wasmgc;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceMap;
public final class ResourceMapHelper {
private ResourceMapHelper() {
}
private static native ResourceMapEntry entry(ResourceMap<?> map, int index);
private static native int entryCount(ResourceMap<?> map);
public static Resource get(ResourceMap<?> map, String key) {
var count = entryCount(map);
var initialIndex = Math.abs(key.hashCode()) % count;
for (var i = initialIndex; i < count; ++i) {
var entry = entry(map, i);
if (entry == null) {
return null;
}
if (entry.getKey().equals(key)) {
return entry.getValue();
}
}
for (var i = 0; i < initialIndex; ++i) {
var entry = entry(map, i);
if (entry == null) {
return null;
}
if (entry.getKey().equals(key)) {
return entry.getValue();
}
}
return null;
}
public static boolean has(ResourceMap<?> map, String key) {
return get(map, key) != null;
}
public static String[] keys(ResourceMap<?> map) {
var count = 0;
var entryCount = entryCount(map);
for (var i = 0; i < entryCount; ++i) {
var entry = entry(map, i);
if (entry != null) {
++count;
}
}
var result = new String[count];
var index = 0;
for (var i = 0; i < entryCount; ++i) {
var entry = entry(map, i);
if (entry != null) {
result[index++] = entry.getKey();
}
}
return result;
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.platform.plugin.wasmgc;
@interface ResourceMarker {
int fieldCount();
}

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.platform.plugin.wasmgc;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
import org.teavm.backend.wasm.model.WasmStructure;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmStructGet;
import org.teavm.model.ValueType;
class ResourceMethodIntrinsic implements WasmGCIntrinsic {
private int fieldIndex;
ResourceMethodIntrinsic(int fieldIndex) {
this.fieldIndex = fieldIndex;
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var structType = (WasmType.CompositeReference) context.typeMapper().mapType(
ValueType.object(invocation.getMethod().getClassName()));
var struct = (WasmStructure) structType.composite;
return new WasmStructGet(struct, context.generate(invocation.getArguments().get(0)), fieldIndex);
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.platform.plugin.wasmgc;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
import org.teavm.backend.wasm.model.WasmArray;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.model.ValueType;
import org.teavm.platform.metadata.ResourceArray;
public class WasmGCResourceArrayIntrinsic implements WasmGCIntrinsic {
@Override
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
switch (invocation.getMethod().getName()) {
case "size":
return new WasmArrayLength(context.generate(invocation.getArguments().get(0)));
case "get":
return new WasmArrayGet(getArrayType(context),
context.generate(invocation.getArguments().get(0)),
context.generate(invocation.getArguments().get(1)));
default:
throw new IllegalArgumentException();
}
}
private WasmArray getArrayType(WasmGCIntrinsicContext context) {
var type = (WasmType.CompositeReference) context.typeMapper().mapType(
ValueType.object(ResourceArray.class.getName()));
return (WasmArray) type.composite;
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.platform.plugin.wasmgc;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
import org.teavm.backend.wasm.model.WasmArray;
import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.model.ValueType;
import org.teavm.platform.metadata.ResourceMap;
public class WasmGCResourceMapHelperIntrinsic implements WasmGCIntrinsic {
@Override
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
switch (invocation.getMethod().getName()) {
case "entryCount":
return new WasmArrayLength(context.generate(invocation.getArguments().get(0)));
case "entry":
return new WasmArrayGet(getArrayType(context),
context.generate(invocation.getArguments().get(0)),
context.generate(invocation.getArguments().get(1)));
default:
throw new IllegalArgumentException();
}
}
private WasmArray getArrayType(WasmGCIntrinsicContext context) {
var type = (WasmType.CompositeReference) context.typeMapper().mapType(
ValueType.object(ResourceMap.class.getName()));
return (WasmArray) type.composite;
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.platform.plugin.wasmgc;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactoryContext;
import org.teavm.common.ServiceRepository;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.MetadataGenerator;
public class WasmGCResourceMetadataIntrinsicFactory implements WasmGCIntrinsicFactory {
private Properties properties;
private ServiceRepository services;
private Map<MethodReference, MetadataGenerator> generators = new HashMap<>();
public WasmGCResourceMetadataIntrinsicFactory(Properties properties, ServiceRepository services) {
this.properties = properties;
this.services = services;
}
public void addGenerator(MethodReference method, MetadataGenerator generator) {
generators.put(method, generator);
}
@Override
public WasmGCIntrinsic createIntrinsic(MethodReference methodRef, WasmGCIntrinsicFactoryContext context) {
var generator = generators.get(methodRef);
return generator != null
? new MetadataIntrinsic(properties, services, generator)
: null;
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.platform.plugin.wasmgc;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactoryContext;
import org.teavm.model.MethodReference;
public class WasmGCResourceMethodIntrinsicFactory implements WasmGCIntrinsicFactory {
@Override
public WasmGCIntrinsic createIntrinsic(MethodReference methodRef, WasmGCIntrinsicFactoryContext context) {
var cls = context.classes().get(methodRef.getClassName());
if (cls == null) {
return null;
}
var method = cls.getMethod(methodRef.getDescriptor());
if (method == null) {
return null;
}
var annot = method.getAnnotations().get(FieldMarker.class.getName());
if (annot == null) {
return null;
}
var index = annot.getValue("index").getInt();
return new ResourceMethodIntrinsic(index);
}
}