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