mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
wasm gc: implement resources
This commit is contained in:
parent
29dec0962b
commit
fea62af09a
|
@ -16,10 +16,17 @@
|
|||
package org.teavm.backend.wasm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
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.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.intrinsics.gc.WasmGCIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory;
|
||||
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsics;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
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.ListableClassHolderSource;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.transformation.BoundCheckInsertion;
|
||||
import org.teavm.model.transformation.NullCheckFilter;
|
||||
|
@ -43,16 +51,34 @@ import org.teavm.vm.TeaVMTarget;
|
|||
import org.teavm.vm.TeaVMTargetController;
|
||||
import org.teavm.vm.spi.TeaVMHostExtension;
|
||||
|
||||
public class WasmGCTarget implements TeaVMTarget {
|
||||
public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||
private TeaVMTargetController controller;
|
||||
private NullCheckInsertion nullCheckInsertion;
|
||||
private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion();
|
||||
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) {
|
||||
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
|
||||
public void setController(TeaVMTargetController controller) {
|
||||
this.controller = controller;
|
||||
|
@ -85,7 +111,7 @@ public class WasmGCTarget implements TeaVMTarget {
|
|||
|
||||
@Override
|
||||
public List<TeaVMHostExtension> getHostExtensions() {
|
||||
return List.of();
|
||||
return List.of(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -114,15 +140,17 @@ public class WasmGCTarget implements TeaVMTarget {
|
|||
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException {
|
||||
var module = new WasmModule();
|
||||
var customGenerators = new WasmGCCustomGenerators();
|
||||
var intrinsics = new WasmGCIntrinsics();
|
||||
var intrinsics = new WasmGCIntrinsics(classes, intrinsicFactories, customIntrinsics);
|
||||
var declarationsGenerator = new WasmGCDeclarationsGenerator(
|
||||
module,
|
||||
classes,
|
||||
controller.getClassLoader(),
|
||||
controller.getClassInitializerInfo(),
|
||||
controller.getDependencyInfo(),
|
||||
controller.getDiagnostics(),
|
||||
customGenerators,
|
||||
intrinsics,
|
||||
customTypeMapperFactories,
|
||||
controller::isVirtual
|
||||
);
|
||||
declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger());
|
||||
|
|
|
@ -75,6 +75,9 @@ public abstract class BaseDisassemblyListener {
|
|||
case ANY:
|
||||
writer.write("anyref");
|
||||
return;
|
||||
case EQ:
|
||||
writer.write("eqref");
|
||||
return;
|
||||
case FUNC:
|
||||
writer.write("funcref");
|
||||
return;
|
||||
|
@ -99,6 +102,9 @@ public abstract class BaseDisassemblyListener {
|
|||
case ANY:
|
||||
writer.write("any");
|
||||
return;
|
||||
case EQ:
|
||||
writer.write("eq");
|
||||
return;
|
||||
case FUNC:
|
||||
writer.write("func");
|
||||
return;
|
||||
|
|
|
@ -815,6 +815,13 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
|||
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
|
||||
public void arrayGet(WasmSignedType signedType, int typeIndex) {
|
||||
writer.address();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -22,6 +22,7 @@ import org.teavm.backend.wasm.WasmFunctionTypes;
|
|||
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.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.WasmGCTypeMapper;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
|
||||
|
@ -49,11 +50,13 @@ public class WasmGCDeclarationsGenerator {
|
|||
public WasmGCDeclarationsGenerator(
|
||||
WasmModule module,
|
||||
ListableClassHolderSource classes,
|
||||
ClassLoader classLoader,
|
||||
ClassInitializerInfo classInitializerInfo,
|
||||
DependencyInfo dependencyInfo,
|
||||
Diagnostics diagnostics,
|
||||
WasmGCCustomGeneratorProvider customGenerators,
|
||||
WasmGCIntrinsicProvider intrinsics,
|
||||
List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories,
|
||||
Predicate<MethodReference> isVirtual
|
||||
) {
|
||||
this.module = module;
|
||||
|
@ -65,6 +68,7 @@ public class WasmGCDeclarationsGenerator {
|
|||
module,
|
||||
hierarchy,
|
||||
classes,
|
||||
classLoader,
|
||||
virtualTables,
|
||||
classInitializerInfo,
|
||||
functionTypes,
|
||||
|
@ -84,7 +88,8 @@ public class WasmGCDeclarationsGenerator {
|
|||
virtualTables,
|
||||
methodGenerator,
|
||||
names,
|
||||
classInitializerInfo
|
||||
classInitializerInfo,
|
||||
customTypeMapperFactories
|
||||
);
|
||||
methodGenerator.setClassInfoProvider(classGenerator);
|
||||
methodGenerator.setStrings(classGenerator.strings);
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.gc.vtable.WasmGCVirtualTable;
|
||||
|
@ -137,7 +138,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
|
||||
ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables,
|
||||
BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names,
|
||||
ClassInitializerInfo classInitializerInfo) {
|
||||
ClassInitializerInfo classInitializerInfo,
|
||||
List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories) {
|
||||
this.module = module;
|
||||
this.classSource = classSource;
|
||||
this.functionTypes = functionTypes;
|
||||
|
@ -152,6 +154,39 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
|||
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes);
|
||||
newArrayGenerator = new WasmGCNewArrayFunctionGenerator(module, functionTypes, this, names);
|
||||
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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -15,7 +15,9 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.generate.gc.classes;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
|
@ -31,6 +33,8 @@ public class WasmGCTypeMapper {
|
|||
private WasmGCClassInfoProvider classInfoProvider;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private WasmModule module;
|
||||
private List<WasmGCCustomTypeMapper> customTypeMappers;
|
||||
private Map<String, WasmType> typeCache = new HashMap<>();
|
||||
|
||||
WasmGCTypeMapper(ClassReaderSource classes, WasmGCClassInfoProvider classInfoProvider,
|
||||
WasmFunctionTypes functionTypes, WasmModule module) {
|
||||
|
@ -40,6 +44,10 @@ public class WasmGCTypeMapper {
|
|||
this.module = module;
|
||||
}
|
||||
|
||||
void setCustomTypeMappers(List<WasmGCCustomTypeMapper> customTypeMappers) {
|
||||
this.customTypeMappers = List.copyOf(customTypeMappers);
|
||||
}
|
||||
|
||||
public WasmStorageType mapStorageType(ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
|
@ -61,7 +69,7 @@ public class WasmGCTypeMapper {
|
|||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else {
|
||||
return classInfoProvider.getClassInfo(type).getType().asStorage();
|
||||
return mapType(type).asStorage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,12 +94,7 @@ public class WasmGCTypeMapper {
|
|||
} else if (type instanceof ValueType.Void) {
|
||||
return null;
|
||||
} else if (type instanceof ValueType.Object) {
|
||||
var className = ((ValueType.Object) type).getClassName();
|
||||
var cls = classes.get(className);
|
||||
if (cls == null) {
|
||||
className = "java.lang.Object";
|
||||
}
|
||||
return classInfoProvider.getClassInfo(className).getType();
|
||||
return mapClassType(((ValueType.Object) type).getClassName());
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
var degree = 0;
|
||||
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) {
|
||||
var returnType = mapType(methodDesc.getResultType());
|
||||
var javaParamTypes = methodDesc.getParameterTypes();
|
||||
|
|
|
@ -52,6 +52,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
private WasmGCTypeMapper typeMapper;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private ListableClassReaderSource classes;
|
||||
private ClassLoader classLoader;
|
||||
private ClassHierarchy hierarchy;
|
||||
private BaseWasmFunctionRepository functions;
|
||||
private WasmGCSupertypeFunctionProvider supertypeFunctions;
|
||||
|
@ -67,7 +68,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
|
||||
public WasmGCGenerationContext(WasmModule module, WasmGCVirtualTableProvider virtualTables,
|
||||
WasmGCTypeMapper typeMapper, WasmFunctionTypes functionTypes, ListableClassReaderSource classes,
|
||||
ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
|
||||
ClassLoader classLoader, ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
|
||||
WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
|
||||
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
|
||||
WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics,
|
||||
|
@ -77,6 +78,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
this.typeMapper = typeMapper;
|
||||
this.functionTypes = functionTypes;
|
||||
this.classes = classes;
|
||||
this.classLoader = classLoader;
|
||||
this.hierarchy = hierarchy;
|
||||
this.functions = functions;
|
||||
this.supertypeFunctions = supertypeFunctions;
|
||||
|
@ -92,6 +94,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
return classInfoProvider;
|
||||
}
|
||||
|
||||
public WasmGCNameProvider names() {
|
||||
return names;
|
||||
}
|
||||
|
||||
public WasmGCStandardClasses standardClasses() {
|
||||
return standardClasses;
|
||||
}
|
||||
|
@ -137,6 +143,10 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
|
|||
return classes;
|
||||
}
|
||||
|
||||
public ClassLoader classLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
public ClassHierarchy hierarchy() {
|
||||
return hierarchy;
|
||||
}
|
||||
|
|
|
@ -30,8 +30,10 @@ import org.teavm.backend.wasm.gc.PreciseTypeInference;
|
|||
import org.teavm.backend.wasm.generate.ExpressionCache;
|
||||
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
|
||||
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.WasmGCTypeMapper;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
||||
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicContext;
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
|
@ -585,6 +587,11 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader classLoader() {
|
||||
return context.classLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmModule module() {
|
||||
return context.module();
|
||||
|
@ -629,5 +636,15 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
|||
public ExpressionCache exprCache() {
|
||||
return exprCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGCNameProvider names() {
|
||||
return context.names();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGCStringProvider strings() {
|
||||
return context.strings();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
|||
private WasmModule module;
|
||||
private ClassHierarchy hierarchy;
|
||||
private ListableClassHolderSource classes;
|
||||
private ClassLoader classLoader;
|
||||
private WasmGCVirtualTableProvider virtualTables;
|
||||
private ClassInitializerInfo classInitInfo;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
|
@ -84,6 +85,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
|||
WasmModule module,
|
||||
ClassHierarchy hierarchy,
|
||||
ListableClassHolderSource classes,
|
||||
ClassLoader classLoader,
|
||||
WasmGCVirtualTableProvider virtualTables,
|
||||
ClassInitializerInfo classInitInfo,
|
||||
WasmFunctionTypes functionTypes,
|
||||
|
@ -95,6 +97,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
|||
this.module = module;
|
||||
this.hierarchy = hierarchy;
|
||||
this.classes = classes;
|
||||
this.classLoader = classLoader;
|
||||
this.virtualTables = virtualTables;
|
||||
this.classInitInfo = classInitInfo;
|
||||
this.functionTypes = functionTypes;
|
||||
|
@ -310,6 +313,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
|||
typeMapper,
|
||||
functionTypes,
|
||||
classes,
|
||||
classLoader,
|
||||
hierarchy,
|
||||
this,
|
||||
supertypeFunctions,
|
||||
|
|
|
@ -21,8 +21,10 @@ import org.teavm.backend.wasm.WasmFunctionTypes;
|
|||
import org.teavm.backend.wasm.gc.PreciseTypeInference;
|
||||
import org.teavm.backend.wasm.generate.ExpressionCache;
|
||||
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.WasmGCTypeMapper;
|
||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.model.ClassHierarchy;
|
||||
|
@ -47,4 +49,10 @@ public interface WasmGCIntrinsicContext {
|
|||
TemporaryVariablePool tempVars();
|
||||
|
||||
ExpressionCache exprCache();
|
||||
|
||||
WasmGCNameProvider names();
|
||||
|
||||
WasmGCStringProvider strings();
|
||||
|
||||
ClassLoader classLoader();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -22,13 +22,20 @@ import java.util.Map;
|
|||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
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();
|
||||
fillObject();
|
||||
fillClass();
|
||||
|
@ -37,49 +44,50 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
|||
fillFloat();
|
||||
fillDouble();
|
||||
fillArray();
|
||||
for (var entry : customIntrinsics.entrySet()) {
|
||||
add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void fillWasmRuntime() {
|
||||
var intrinsic = new WasmRuntimeIntrinsic();
|
||||
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);
|
||||
intrinsics.put(new MethodReference(WasmRuntime.class, "gt", cls, cls, boolean.class), intrinsic);
|
||||
add(new MethodReference(WasmRuntime.class, "lt", 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)) {
|
||||
intrinsics.put(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, "ltu", 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)) {
|
||||
intrinsics.put(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, "min", cls, cls, cls), intrinsic);
|
||||
add(new MethodReference(WasmRuntime.class, "max", cls, cls, cls), intrinsic);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillObject() {
|
||||
var objectIntrinsics = new ObjectIntrinsic();
|
||||
intrinsics.put(new MethodReference(Object.class, "getClass", Class.class), objectIntrinsics);
|
||||
intrinsics.put(new MethodReference(Object.class.getName(), "getMonitor",
|
||||
ValueType.object("java.lang.Object$Monitor")), objectIntrinsics);
|
||||
intrinsics.put(new MethodReference(Object.class.getName(), "setMonitor",
|
||||
ValueType.object("java.lang.Object$Monitor"), ValueType.VOID), objectIntrinsics);
|
||||
intrinsics.put(new MethodReference(Object.class.getName(), "wasmGCIdentity", ValueType.INTEGER),
|
||||
objectIntrinsics);
|
||||
intrinsics.put(new MethodReference(Object.class.getName(), "setWasmGCIdentity", ValueType.INTEGER,
|
||||
ValueType.VOID), objectIntrinsics);
|
||||
var intrinsic = new ObjectIntrinsic();
|
||||
add(new MethodReference(Object.class, "getClass", Class.class), intrinsic);
|
||||
add(new MethodReference(Object.class.getName(), "getMonitor",
|
||||
ValueType.object("java.lang.Object$Monitor")), intrinsic);
|
||||
add(new MethodReference(Object.class.getName(), "setMonitor",
|
||||
ValueType.object("java.lang.Object$Monitor"), ValueType.VOID), intrinsic);
|
||||
add(new MethodReference(Object.class.getName(), "wasmGCIdentity", ValueType.INTEGER), intrinsic);
|
||||
add(new MethodReference(Object.class.getName(), "setWasmGCIdentity", ValueType.INTEGER,
|
||||
ValueType.VOID), intrinsic);
|
||||
}
|
||||
|
||||
private void fillClass() {
|
||||
var intrinsic = new ClassIntrinsics();
|
||||
intrinsics.put(new MethodReference(Class.class, "getComponentType", Class.class), intrinsic);
|
||||
intrinsics.put(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, "getComponentType", Class.class), intrinsic);
|
||||
add(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic);
|
||||
add(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic);
|
||||
}
|
||||
|
||||
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());
|
||||
intrinsics.put(new MethodReference(System.class, "currentTimeMillis", long.class),
|
||||
new SystemIntrinsic());
|
||||
add(new MethodReference(System.class, "currentTimeMillis", long.class), new SystemIntrinsic());
|
||||
}
|
||||
|
||||
private void fillLongAndInteger() {
|
||||
|
@ -89,42 +97,70 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
|||
|
||||
private void fillIntNum(Class<?> javaClass, Class<?> wrapperClass, WasmIntType wasmType) {
|
||||
var intrinsic = new IntNumIntrinsic(javaClass, wasmType);
|
||||
intrinsics.put(new MethodReference(wrapperClass, "divideUnsigned", javaClass, javaClass, javaClass),
|
||||
intrinsic);
|
||||
intrinsics.put(new MethodReference(wrapperClass, "remainderUnsigned", javaClass, javaClass, javaClass),
|
||||
intrinsic);
|
||||
intrinsics.put(new MethodReference(wrapperClass, "compareUnsigned", javaClass, javaClass, int.class),
|
||||
intrinsic);
|
||||
add(new MethodReference(wrapperClass, "divideUnsigned", javaClass, javaClass, javaClass), intrinsic);
|
||||
add(new MethodReference(wrapperClass, "remainderUnsigned", javaClass, javaClass, javaClass), intrinsic);
|
||||
add(new MethodReference(wrapperClass, "compareUnsigned", javaClass, javaClass, int.class), intrinsic);
|
||||
}
|
||||
|
||||
private void fillFloat() {
|
||||
var intrinsic = new FloatIntrinsic();
|
||||
intrinsics.put(new MethodReference(Float.class, "getNaN", float.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(Float.class, "isNaN", float.class, boolean.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(Float.class, "isInfinite", float.class, boolean.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(Float.class, "isFinite", float.class, boolean.class), intrinsic);
|
||||
intrinsics.put(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, "getNaN", float.class), intrinsic);
|
||||
add(new MethodReference(Float.class, "isNaN", float.class, boolean.class), intrinsic);
|
||||
add(new MethodReference(Float.class, "isInfinite", float.class, boolean.class), intrinsic);
|
||||
add(new MethodReference(Float.class, "isFinite", float.class, boolean.class), intrinsic);
|
||||
add(new MethodReference(Float.class, "floatToRawIntBits", float.class, int.class), intrinsic);
|
||||
add(new MethodReference(Float.class, "intBitsToFloat", int.class, float.class), intrinsic);
|
||||
}
|
||||
|
||||
private void fillDouble() {
|
||||
var intrinsic = new DoubleIntrinsic();
|
||||
intrinsics.put(new MethodReference(Double.class, "getNaN", double.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(Double.class, "isNaN", double.class, boolean.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(Double.class, "isInfinite", double.class, boolean.class), intrinsic);
|
||||
intrinsics.put(new MethodReference(Double.class, "isFinite", double.class, boolean.class), intrinsic);
|
||||
intrinsics.put(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, "getNaN", double.class), intrinsic);
|
||||
add(new MethodReference(Double.class, "isNaN", double.class, boolean.class), intrinsic);
|
||||
add(new MethodReference(Double.class, "isInfinite", double.class, boolean.class), intrinsic);
|
||||
add(new MethodReference(Double.class, "isFinite", double.class, boolean.class), intrinsic);
|
||||
add(new MethodReference(Double.class, "doubleToRawLongBits", double.class, long.class), intrinsic);
|
||||
add(new MethodReference(Double.class, "longBitsToDouble", long.class, double.class), intrinsic);
|
||||
}
|
||||
|
||||
private void fillArray() {
|
||||
var intrinsic = new ArrayIntrinsic();
|
||||
intrinsics.put(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, "getLength", Object.class, int.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
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.function.Supplier;
|
|||
|
||||
public class WasmArray extends WasmCompositeType {
|
||||
private WasmStorageType elementType;
|
||||
private boolean immutable;
|
||||
private Supplier<WasmStorageType> elementTypeSupplier;
|
||||
|
||||
public WasmArray(String name, WasmStorageType elementType) {
|
||||
|
@ -40,6 +41,14 @@ public class WasmArray extends WasmCompositeType {
|
|||
return elementType;
|
||||
}
|
||||
|
||||
public boolean isImmutable() {
|
||||
return immutable;
|
||||
}
|
||||
|
||||
public void setImmutable(boolean immutable) {
|
||||
this.immutable = immutable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
|
|
@ -22,6 +22,7 @@ public class WasmField {
|
|||
int index;
|
||||
private String name;
|
||||
private WasmStorageType type;
|
||||
private boolean immutable;
|
||||
|
||||
public WasmField(WasmStorageType type, String name) {
|
||||
this(type);
|
||||
|
@ -56,6 +57,14 @@ public class WasmField {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isImmutable() {
|
||||
return immutable;
|
||||
}
|
||||
|
||||
public void setImmutable(boolean immutable) {
|
||||
this.immutable = immutable;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
if (structure == null) {
|
||||
return -1;
|
||||
|
|
|
@ -59,6 +59,7 @@ public abstract class WasmType {
|
|||
public static abstract class Reference extends WasmType {
|
||||
public static final SpecialReference FUNC = SpecialReferenceKind.FUNC.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 STRUCT = SpecialReferenceKind.STRUCT.asType();
|
||||
public static final SpecialReference ARRAY = SpecialReferenceKind.ARRAY.asType();
|
||||
|
@ -96,6 +97,7 @@ public abstract class WasmType {
|
|||
public enum SpecialReferenceKind {
|
||||
FUNC,
|
||||
ANY,
|
||||
EQ,
|
||||
EXTERN,
|
||||
STRUCT,
|
||||
ARRAY,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -283,6 +283,13 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor {
|
|||
expression.getLength().acceptVisitor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayNewFixed expression) {
|
||||
for (var element : expression.getElements()) {
|
||||
element.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayGet expression) {
|
||||
expression.getInstance().acceptVisitor(this);
|
||||
|
|
|
@ -108,6 +108,8 @@ public interface WasmExpressionVisitor {
|
|||
|
||||
void visit(WasmArrayNewDefault expression);
|
||||
|
||||
void visit(WasmArrayNewFixed expression);
|
||||
|
||||
void visit(WasmArrayGet expression);
|
||||
|
||||
void visit(WasmArraySet expression);
|
||||
|
|
|
@ -336,6 +336,11 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor {
|
|||
expression.setLength(mapper.apply(expression.getLength()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayNewFixed expression) {
|
||||
replaceExpressions(expression.getElements());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayGet expression) {
|
||||
expression.getInstance().acceptVisitor(this);
|
||||
|
|
|
@ -156,6 +156,9 @@ public interface CodeListener {
|
|||
default void arrayNewDefault(int typeIndex) {
|
||||
}
|
||||
|
||||
default void arrayNewFixed(int typeIndex, int size) {
|
||||
}
|
||||
|
||||
default void arrayGet(WasmSignedType signedType, int typeIndex) {
|
||||
}
|
||||
|
||||
|
|
|
@ -660,6 +660,9 @@ public class CodeParser extends BaseSectionParser {
|
|||
case 7:
|
||||
codeListener.arrayNewDefault(readLEB());
|
||||
return true;
|
||||
case 8:
|
||||
codeListener.arrayNewFixed(readLEB(), readLEB());
|
||||
return true;
|
||||
|
||||
case 11:
|
||||
codeListener.arrayGet(null, readLEB());
|
||||
|
|
|
@ -92,6 +92,8 @@ public class WasmBinaryReader {
|
|||
return special(WasmType.SpecialReferenceKind.EXTERN, nullable);
|
||||
case 0x6E:
|
||||
return special(WasmType.SpecialReferenceKind.ANY, nullable);
|
||||
case 0x6D:
|
||||
return special(WasmType.SpecialReferenceKind.EQ, nullable);
|
||||
case 0x6C:
|
||||
return special(WasmType.SpecialReferenceKind.I31, nullable);
|
||||
case 0x6B:
|
||||
|
|
|
@ -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.WasmArrayLength;
|
||||
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.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -1155,6 +1156,19 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
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
|
||||
public void visit(WasmArrayGet expression) {
|
||||
pushLocation(expression);
|
||||
|
|
|
@ -65,6 +65,9 @@ public class WasmBinaryWriter {
|
|||
case ANY:
|
||||
writeByte(0x6e);
|
||||
break;
|
||||
case EQ:
|
||||
writeByte(0x6d);
|
||||
break;
|
||||
case EXTERN:
|
||||
writeByte(0x6f);
|
||||
break;
|
||||
|
|
|
@ -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.WasmArrayLength;
|
||||
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.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -1203,6 +1204,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
unsupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayNewFixed expression) {
|
||||
unsupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayGet expression) {
|
||||
unsupported();
|
||||
|
|
|
@ -44,7 +44,7 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
|
|||
section.writeLEB(type.getFields().size());
|
||||
for (var fieldType : type.getFields()) {
|
||||
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) {
|
||||
section.writeByte(0x5E);
|
||||
writeStorageType(type.getElementType());
|
||||
section.writeLEB(0x01); // mutable
|
||||
section.writeLEB(type.isImmutable() ? 0 : 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.WasmArrayLength;
|
||||
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.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -765,6 +766,17 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
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
|
||||
public void visit(WasmArrayGet expression) {
|
||||
open();
|
||||
|
|
|
@ -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.WasmArrayLength;
|
||||
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.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -311,6 +312,11 @@ public class WasmTypeInference implements WasmExpressionVisitor {
|
|||
result = expression.getType().getReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayNewFixed expression) {
|
||||
result = expression.getType().getReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArrayGet expression) {
|
||||
result = expression.getType().getElementType().asUnpackedType();
|
||||
|
|
|
@ -26,14 +26,14 @@ import org.teavm.platform.metadata.ResourceArray;
|
|||
import org.teavm.platform.metadata.ResourceMap;
|
||||
import org.teavm.platform.metadata.StaticFieldResource;
|
||||
|
||||
class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
|
||||
public class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
|
||||
private ClassReaderSource classSource;
|
||||
private ClassLoader classLoader;
|
||||
private Properties properties;
|
||||
private BuildTimeResourceProxyBuilder proxyBuilder;
|
||||
private ServiceRepository services;
|
||||
|
||||
DefaultMetadataGeneratorContext(ClassReaderSource classSource, ClassLoader classLoader,
|
||||
public DefaultMetadataGeneratorContext(ClassReaderSource classSource, ClassLoader classLoader,
|
||||
Properties properties, ServiceRepository services) {
|
||||
this.classSource = classSource;
|
||||
this.classLoader = classLoader;
|
||||
|
|
|
@ -23,8 +23,10 @@ import org.teavm.backend.c.intrinsic.Intrinsic;
|
|||
import org.teavm.backend.c.intrinsic.IntrinsicContext;
|
||||
import org.teavm.backend.javascript.TeaVMJavaScriptHost;
|
||||
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.WasmIntrinsicManager;
|
||||
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.PlatformMarker;
|
||||
|
@ -34,6 +36,18 @@ import org.teavm.model.MethodReference;
|
|||
import org.teavm.platform.Platform;
|
||||
import org.teavm.platform.PlatformQueue;
|
||||
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.spi.TeaVMHost;
|
||||
import org.teavm.vm.spi.TeaVMPlugin;
|
||||
|
@ -44,8 +58,8 @@ public class PlatformPlugin implements TeaVMPlugin, MetadataRegistration {
|
|||
|
||||
@Override
|
||||
public void install(TeaVMHost host) {
|
||||
host.add(metadataTransformer);
|
||||
if (host.getExtension(TeaVMJavaScriptHost.class) != null) {
|
||||
host.add(metadataTransformer);
|
||||
host.add(new ResourceTransformer());
|
||||
host.add(new ResourceAccessorTransformer(host));
|
||||
host.add(new ResourceAccessorDependencyListener());
|
||||
|
@ -67,55 +81,23 @@ public class PlatformPlugin implements TeaVMPlugin, MetadataRegistration {
|
|||
|
||||
metadataGeneratorConsumers.add((method, constructor, generator) -> jsHost.add(method,
|
||||
new MetadataProviderNativeGenerator(generator, constructor)));
|
||||
} else if (!isBootstrap()) {
|
||||
host.add(new StringAmplifierTransformer());
|
||||
}
|
||||
|
||||
if (!isBootstrap()) {
|
||||
TeaVMWasmHost wasmHost = host.getExtension(TeaVMWasmHost.class);
|
||||
var wasmHost = host.getExtension(TeaVMWasmHost.class);
|
||||
if (wasmHost != null) {
|
||||
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));
|
||||
}
|
||||
});
|
||||
installWasm(host, wasmHost);
|
||||
}
|
||||
|
||||
TeaVMCHost cHost = host.getExtension(TeaVMCHost.class);
|
||||
var cHost = host.getExtension(TeaVMCHost.class);
|
||||
if (cHost != null) {
|
||||
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());
|
||||
}
|
||||
installC(host, cHost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(IntrinsicContext context, InvocationExpr invocation) {
|
||||
context.emit(invocation.getArguments().get(0));
|
||||
}
|
||||
});
|
||||
var wasmGCHost = host.getExtension(TeaVMWasmGCHost.class);
|
||||
if (wasmGCHost != null) {
|
||||
installWasmGC(host, wasmGCHost);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +113,91 @@ public class PlatformPlugin implements TeaVMPlugin, MetadataRegistration {
|
|||
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
|
||||
public void register(MethodReference method, MetadataGenerator generator) {
|
||||
MethodReference constructor = new MethodReference(method.getClassName(), method.getName() + "$$create",
|
||||
|
|
|
@ -78,11 +78,7 @@ class ResourceProgramTransformer {
|
|||
|
||||
private void removeCastToResource(CastInstruction cast) {
|
||||
if (!cast.isWeak() && hierarchy.isSuperType(RESOURCE, cast.getTargetType(), false)) {
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setReceiver(cast.getReceiver());
|
||||
assign.setAssignee(cast.getValue());
|
||||
assign.setLocation(cast.getLocation());
|
||||
cast.replace(assign);
|
||||
cast.setWeak(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user