mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm: add model definitions for GC spec
- refactor Wasm type representation to include reference types - refactor function representation for consistency with new type system First step toward Wasm GC support
This commit is contained in:
parent
55657036a1
commit
d6474c3aeb
|
@ -70,7 +70,7 @@ public class ServiceLoaderWasmSupport implements WasmIntrinsicFactory {
|
|||
var table = createServiceData(manager);
|
||||
var tableArg = new WasmInt32Constant(table);
|
||||
var serviceClassAddress = manager.generate(invocation.getArguments().get(0));
|
||||
return new WasmCall(manager.getNames().forMethod(CREATE_SERVICES_METHOD), tableArg,
|
||||
return new WasmCall(manager.getFunctions().forStaticMethod(CREATE_SERVICES_METHOD), tableArg,
|
||||
serviceClassAddress);
|
||||
}
|
||||
|
||||
|
@ -94,10 +94,10 @@ public class ServiceLoaderWasmSupport implements WasmIntrinsicFactory {
|
|||
var implPointer = manager.getClassPointer(ValueType.object(implementation));
|
||||
entry.setAddress(0, implPointer);
|
||||
|
||||
var constructorName = manager.getNames().forMethod(new MethodReference(
|
||||
var constructorFn = manager.getFunctions().forInstanceMethod(new MethodReference(
|
||||
implementation, "<init>", ValueType.VOID
|
||||
));
|
||||
entry.setInt(1, manager.getFunctionPointer(constructorName));
|
||||
entry.setInt(1, manager.getFunctionPointer(constructorFn));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.generate.WasmGeneratorUtil;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmFunctionRepository {
|
||||
private WasmModule module;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private NameProvider nameProvider;
|
||||
private Map<MethodReference, WasmFunction> staticMethods = new HashMap<>();
|
||||
private Map<MethodReference, WasmFunction> instanceMethods = new HashMap<>();
|
||||
private Map<String, WasmFunction> classInitializers = new HashMap<>();
|
||||
private Map<ValueType, WasmFunction> supertypes = new HashMap<>();
|
||||
|
||||
public WasmFunctionRepository(WasmModule module, WasmFunctionTypes functionTypes, NameProvider nameProvider) {
|
||||
this.module = module;
|
||||
this.functionTypes = functionTypes;
|
||||
this.nameProvider = nameProvider;
|
||||
}
|
||||
|
||||
public WasmFunction forMethod(MethodReader method) {
|
||||
return forMethod(method.getReference(), method.hasModifier(ElementModifier.STATIC));
|
||||
}
|
||||
|
||||
public WasmFunction forMethod(MethodReference reference, boolean isStatic) {
|
||||
return isStatic ? forStaticMethod(reference) : forInstanceMethod(reference);
|
||||
}
|
||||
|
||||
public WasmFunction forStaticMethod(MethodReference reference) {
|
||||
return staticMethods.computeIfAbsent(reference, key -> {
|
||||
var wasmParams = new WasmType[key.parameterCount()];
|
||||
for (var i = 0; i < key.parameterCount(); ++i) {
|
||||
wasmParams[i] = WasmGeneratorUtil.mapType(reference.parameterType(i));
|
||||
}
|
||||
var wasmType = functionTypes.of(WasmGeneratorUtil.mapType(key.getReturnType()), wasmParams);
|
||||
var wasmFunction = new WasmFunction(wasmType);
|
||||
wasmFunction.setName(nameProvider.forMethod(key));
|
||||
wasmFunction.setJavaMethod(key);
|
||||
module.functions.add(wasmFunction);
|
||||
return wasmFunction;
|
||||
});
|
||||
}
|
||||
|
||||
public WasmFunction forInstanceMethod(MethodReference reference) {
|
||||
return instanceMethods.computeIfAbsent(reference, key -> {
|
||||
var wasmParams = new WasmType[key.parameterCount() + 1];
|
||||
wasmParams[0] = WasmGeneratorUtil.mapType(ValueType.object(reference.getClassName()));
|
||||
for (var i = 0; i < key.parameterCount(); ++i) {
|
||||
wasmParams[i + 1] = WasmGeneratorUtil.mapType(reference.parameterType(i));
|
||||
}
|
||||
var wasmType = functionTypes.of(WasmGeneratorUtil.mapType(key.getReturnType()), wasmParams);
|
||||
var wasmFunction = new WasmFunction(wasmType);
|
||||
wasmFunction.setName(nameProvider.forMethod(key));
|
||||
wasmFunction.setJavaMethod(key);
|
||||
module.functions.add(wasmFunction);
|
||||
return wasmFunction;
|
||||
});
|
||||
}
|
||||
|
||||
public WasmFunction forClassInitializer(String className) {
|
||||
return classInitializers.computeIfAbsent(className, key -> {
|
||||
var wasmFunction = new WasmFunction(functionTypes.of(null));
|
||||
wasmFunction.setName(nameProvider.forClassInitializer(key));
|
||||
module.functions.add(wasmFunction);
|
||||
return wasmFunction;
|
||||
});
|
||||
}
|
||||
|
||||
public WasmFunction forSupertype(ValueType type) {
|
||||
return supertypes.computeIfAbsent(type, key -> {
|
||||
var wasmFunction = new WasmFunction(functionTypes.of(WasmType.INT32, WasmType.INT32));
|
||||
wasmFunction.setName(nameProvider.forSupertypeFunction(key));
|
||||
module.functions.add(wasmFunction);
|
||||
return wasmFunction;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.render.WasmSignature;
|
||||
|
||||
public class WasmFunctionTypes {
|
||||
private WasmModule module;
|
||||
private Map<WasmSignature, WasmFunctionType> types = new HashMap<>();
|
||||
|
||||
public WasmFunctionTypes(WasmModule module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public WasmFunctionType get(WasmSignature signature) {
|
||||
return types.computeIfAbsent(signature, k -> {
|
||||
var type = new WasmFunctionType(signature.getReturnType(), signature.getParameterTypes());
|
||||
module.types.add(type);
|
||||
return type;
|
||||
});
|
||||
}
|
||||
|
||||
public WasmFunctionType of(WasmType returnType, WasmType... parameterTypes) {
|
||||
return get(new WasmSignature(returnType, parameterTypes));
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@ import org.teavm.ast.InvocationExpr;
|
|||
import org.teavm.ast.decompilation.Decompiler;
|
||||
import org.teavm.backend.lowlevel.analyze.LowLevelInliningFilterFactory;
|
||||
import org.teavm.backend.lowlevel.dependency.StringsDependencyListener;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.lowlevel.generate.NameProviderWithSpecialNames;
|
||||
import org.teavm.backend.lowlevel.transform.CoroutineTransformation;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
|
@ -107,6 +106,7 @@ import org.teavm.backend.wasm.model.expression.WasmReturn;
|
|||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
|
||||
import org.teavm.backend.wasm.optimization.UnusedFunctionElimination;
|
||||
import org.teavm.backend.wasm.optimization.UnusedTypeElimination;
|
||||
import org.teavm.backend.wasm.render.ReportingWasmBinaryStatsCollector;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
||||
|
@ -475,7 +475,6 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
|
||||
var statsCollector = this.statsCollector != null ? this.statsCollector : WasmBinaryStatsCollector.EMPTY;
|
||||
WasmModule module = new WasmModule();
|
||||
WasmFunction initFunction = new WasmFunction("__start__");
|
||||
|
||||
var vtableProvider = createVirtualTableProvider(classes);
|
||||
ClassHierarchy hierarchy = new ClassHierarchy(classes);
|
||||
|
@ -491,20 +490,24 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
var dwarfClassGen = debugging
|
||||
? new DwarfClassGenerator(dwarfGenerator.getInfoWriter(), dwarfGenerator.strings)
|
||||
: null;
|
||||
var functionTypes = new WasmFunctionTypes(module);
|
||||
var functions = new WasmFunctionRepository(module, functionTypes, names);
|
||||
var classGenerator = new WasmClassGenerator(classes, controller.getUnprocessedClassSource(),
|
||||
vtableProvider, tagRegistry, binaryWriter, names, metadataRequirements,
|
||||
vtableProvider, tagRegistry, binaryWriter, functions, module, metadataRequirements,
|
||||
controller.getClassInitializerInfo(), characteristics, dwarfClassGen, statsCollector);
|
||||
|
||||
Decompiler decompiler = new Decompiler(classes, new HashSet<>(), false);
|
||||
var stringPool = classGenerator.getStringPool();
|
||||
WasmTag exceptionTag = null;
|
||||
if (exceptionsUsed) {
|
||||
exceptionTag = new WasmTag();
|
||||
module.addTag(exceptionTag);
|
||||
exceptionTag = new WasmTag(functionTypes.of(null));
|
||||
module.tags.add(exceptionTag);
|
||||
}
|
||||
var context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
||||
var context = new WasmGenerationContext(classes, module, functionTypes, functions, controller.getDiagnostics(),
|
||||
vtableProvider, tagRegistry, stringPool, names, characteristics, exceptionTag);
|
||||
|
||||
var initFunction = new WasmFunction(functionTypes.of(null));
|
||||
|
||||
context.addIntrinsic(new AddressIntrinsic(classGenerator));
|
||||
context.addIntrinsic(new StructureIntrinsic(classes, classGenerator));
|
||||
context.addIntrinsic(new FunctionIntrinsic(classGenerator));
|
||||
|
@ -550,11 +553,11 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
asyncMethods::contains);
|
||||
|
||||
generateMethods(classes, context, generator, classGenerator, binaryWriter, module, dwarfClassGen);
|
||||
new WasmInteropFunctionGenerator(classGenerator).generateFunctions(module);
|
||||
new WasmInteropFunctionGenerator(classGenerator, functionTypes).generateFunctions(module);
|
||||
exceptionHandlingIntrinsic.postProcess(context.callSites);
|
||||
generateIsSupertypeFunctions(tagRegistry, module, classGenerator);
|
||||
generateIsSupertypeFunctions(tagRegistry, classGenerator, functions);
|
||||
classGenerator.postProcess();
|
||||
new WasmSpecialFunctionGenerator(classGenerator, gcIntrinsic.regionSizeExpressions)
|
||||
new WasmSpecialFunctionGenerator(classGenerator, functionTypes, gcIntrinsic.regionSizeExpressions)
|
||||
.generateSpecialFunctions(module);
|
||||
mutatorIntrinsic.setStaticGcRootsAddress(classGenerator.getStaticGcRootsAddress());
|
||||
mutatorIntrinsic.setClassesAddress(classGenerator.getClassesAddress());
|
||||
|
@ -566,30 +569,25 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
module.getSegments().add(dataSegment);
|
||||
|
||||
renderMemoryLayout(module, binaryWriter.getAddress(), gcIntrinsic);
|
||||
renderClinit(classes, classGenerator, module);
|
||||
renderClinit(classes, classGenerator, functions);
|
||||
if (controller.wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
generateInitFunction(classes, initFunction, names, binaryWriter.getAddress());
|
||||
module.add(initFunction);
|
||||
generateInitFunction(classes, initFunction, functions, binaryWriter.getAddress());
|
||||
module.functions.add(initFunction);
|
||||
module.setStartFunction(initFunction);
|
||||
module.add(createStartFunction(names));
|
||||
module.add(createStartCallerFunction(names));
|
||||
|
||||
for (String functionName : classGenerator.getFunctionTable()) {
|
||||
WasmFunction function = module.getFunctions().get(functionName);
|
||||
assert function != null : "Function referenced from function table not found: " + functionName;
|
||||
module.getFunctionTable().add(function);
|
||||
}
|
||||
module.functions.add(createStartFunction(functionTypes, functions));
|
||||
module.functions.add(createStartCallerFunction(functionTypes, functions));
|
||||
|
||||
new UnusedFunctionElimination(module).apply();
|
||||
new UnusedTypeElimination(module).apply();
|
||||
|
||||
if (Boolean.parseBoolean(System.getProperty("wasm.memoryTrace", "false"))) {
|
||||
new MemoryAccessTraceTransformation(module).apply();
|
||||
new MemoryAccessTraceTransformation(module, functionTypes).apply();
|
||||
}
|
||||
if (Boolean.parseBoolean(System.getProperty("wasm.indirectCallTrace", "false"))) {
|
||||
new IndirectCallTraceTransformation(module).apply();
|
||||
new IndirectCallTraceTransformation(module, functionTypes).apply();
|
||||
}
|
||||
|
||||
writeBinaryWasm(buildTarget, outputName, module, classGenerator, dwarfGenerator, dwarfClassGen,
|
||||
|
@ -669,27 +667,31 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
};
|
||||
}
|
||||
|
||||
private WasmFunction createStartFunction(NameProvider names) {
|
||||
var function = new WasmFunction("teavm_start");
|
||||
private WasmFunction createStartFunction(WasmFunctionTypes functionTypes, WasmFunctionRepository functions) {
|
||||
var function = new WasmFunction(functionTypes.of(null, WasmType.INT32));
|
||||
function.setName("teavm_start");
|
||||
function.setExportName("start");
|
||||
function.getParameters().add(WasmType.INT32);
|
||||
|
||||
var local = new WasmLocal(WasmType.INT32, "args");
|
||||
function.add(local);
|
||||
|
||||
var call = new WasmCall(names.forMethod(new MethodReference(WasmSupport.class, "runWithArgs",
|
||||
String[].class, void.class)));
|
||||
var runWithArgsFunction = functions.forStaticMethod(new MethodReference(WasmSupport.class, "runWithArgs",
|
||||
String[].class, void.class));
|
||||
var call = new WasmCall(runWithArgsFunction);
|
||||
call.getArguments().add(new WasmGetLocal(local));
|
||||
function.getBody().add(call);
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
private WasmFunction createStartCallerFunction(NameProvider names) {
|
||||
var function = new WasmFunction("teavm_call_start");
|
||||
private WasmFunction createStartCallerFunction(WasmFunctionTypes functionTypes, WasmFunctionRepository functions) {
|
||||
var function = new WasmFunction(functionTypes.of(null));
|
||||
function.setExportName("_start");
|
||||
function.setName("teavm_call_start");
|
||||
|
||||
var call = new WasmCall(names.forMethod(new MethodReference(WasmSupport.class, "runWithoutArgs", void.class)));
|
||||
var runWithoutArgsFunction = functions.forStaticMethod(new MethodReference(WasmSupport.class, "runWithoutArgs",
|
||||
void.class));
|
||||
var call = new WasmCall(runWithoutArgsFunction);
|
||||
function.getBody().add(call);
|
||||
|
||||
return function;
|
||||
|
@ -718,7 +720,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
}
|
||||
|
||||
private void generateInitFunction(ListableClassReaderSource classes, WasmFunction initFunction,
|
||||
NameProvider names, int heapAddress) {
|
||||
WasmFunctionRepository functions, int heapAddress) {
|
||||
|
||||
for (Class<?> javaCls : new Class<?>[] { WasmRuntime.class, WasmHeap.class }) {
|
||||
ClassReader cls = classes.get(javaCls.getName());
|
||||
|
@ -726,10 +728,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
if (clinit == null) {
|
||||
continue;
|
||||
}
|
||||
initFunction.getBody().add(new WasmCall(names.forClassInitializer(cls.getName())));
|
||||
initFunction.getBody().add(new WasmCall(functions.forClassInitializer(cls.getName())));
|
||||
}
|
||||
|
||||
initFunction.getBody().add(new WasmCall(names.forMethod(INIT_HEAP_REF),
|
||||
initFunction.getBody().add(new WasmCall(functions.forStaticMethod(INIT_HEAP_REF),
|
||||
new WasmInt32Constant(heapAddress), new WasmInt32Constant(minHeapSize),
|
||||
new WasmInt32Constant(maxHeapSize), new WasmInt32Constant(WasmHeap.DEFAULT_STACK_SIZE),
|
||||
new WasmInt32Constant(WasmHeap.DEFAULT_BUFFER_SIZE)));
|
||||
|
@ -740,7 +742,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
if (clinit == null) {
|
||||
continue;
|
||||
}
|
||||
initFunction.getBody().add(new WasmCall(names.forClassInitializer(cls.getName())));
|
||||
initFunction.getBody().add(new WasmCall(functions.forClassInitializer(cls.getName())));
|
||||
}
|
||||
|
||||
for (String className : classes.getClassNames()) {
|
||||
|
@ -756,7 +758,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
if (clinit == null) {
|
||||
continue;
|
||||
}
|
||||
initFunction.getBody().add(new WasmCall(names.forClassInitializer(className)));
|
||||
initFunction.getBody().add(new WasmCall(functions.forClassInitializer(className)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -767,7 +769,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
}
|
||||
|
||||
private void emitWast(WasmModule module, BuildTarget buildTarget, String outputName) throws IOException {
|
||||
WasmRenderer renderer = new WasmRenderer();
|
||||
WasmRenderer renderer = new WasmRenderer(module);
|
||||
renderer.setLineNumbersEmitted(debugging);
|
||||
renderer.render(module);
|
||||
try (OutputStream output = buildTarget.createResource(outputName);
|
||||
|
@ -777,7 +779,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
}
|
||||
|
||||
private void emitC(WasmModule module, BuildTarget buildTarget, String outputName) throws IOException {
|
||||
WasmCRenderer renderer = new WasmCRenderer();
|
||||
var renderer = new WasmCRenderer(module);
|
||||
renderer.setLineNumbersEmitted(cLineNumbersEmitted);
|
||||
renderer.setMemoryAccessChecked(Boolean.parseBoolean(System.getProperty("wasm.c.assertMemory", "false")));
|
||||
renderer.render(module);
|
||||
|
@ -814,13 +816,12 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
|| context.getIntrinsic(method.getReference()) != null) {
|
||||
continue;
|
||||
}
|
||||
module.add(generator.generateDefinition(method.getReference()));
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
var methodGeneratorContext = new MethodGeneratorContextImpl(binaryWriter,
|
||||
context.getStringPool(), context.getDiagnostics(), context.names, classGenerator, classes);
|
||||
context.getStringPool(), context.getDiagnostics(), context.functions, classGenerator, classes);
|
||||
|
||||
for (MethodHolder method : methods) {
|
||||
ClassHolder cls = classes.get(method.getOwnerName());
|
||||
|
@ -847,7 +848,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
if (implementor.hasModifier(ElementModifier.NATIVE)) {
|
||||
var methodGenerator = context.getGenerator(method.getReference());
|
||||
if (methodGenerator != null) {
|
||||
WasmFunction function = context.getFunction(context.names.forMethod(method.getReference()));
|
||||
var function = context.functions.forMethod(method);
|
||||
methodGenerator.apply(method.getReference(), function, methodGeneratorContext);
|
||||
} else if (!isShadowStackMethod(method.getReference())) {
|
||||
if (context.getImportedMethod(method.getReference()) == null) {
|
||||
|
@ -855,7 +856,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
controller.getDiagnostics().error(location, "Method {{m0}} is native but "
|
||||
+ "has no {{c1}} annotation on it", method.getReference(), Import.class.getName());
|
||||
}
|
||||
generator.generateNative(method.getReference());
|
||||
generator.generateNative(method);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -865,7 +866,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
if (method == implementor) {
|
||||
generator.generate(method.getReference(), implementor);
|
||||
} else {
|
||||
generateStub(context.names, module, method, implementor);
|
||||
generateStub(context.functions, method, implementor);
|
||||
}
|
||||
if (dwarfClassGen != null) {
|
||||
var dwarfClass = dwarfClassGen.getClass(method.getOwnerName());
|
||||
|
@ -894,13 +895,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
}
|
||||
}
|
||||
|
||||
private void generateIsSupertypeFunctions(TagRegistry tagRegistry, WasmModule module,
|
||||
WasmClassGenerator classGenerator) {
|
||||
private void generateIsSupertypeFunctions(TagRegistry tagRegistry, WasmClassGenerator classGenerator,
|
||||
WasmFunctionRepository functions) {
|
||||
for (ValueType type : classGenerator.getRegisteredClasses()) {
|
||||
WasmFunction function = new WasmFunction(classGenerator.names.forSupertypeFunction(type));
|
||||
function.getParameters().add(WasmType.INT32);
|
||||
function.setResult(WasmType.INT32);
|
||||
module.add(function);
|
||||
var function = functions.forSupertype(type);
|
||||
|
||||
WasmLocal subtypeVar = new WasmLocal(WasmType.INT32, "subtype");
|
||||
function.add(subtypeVar);
|
||||
|
@ -910,7 +908,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
generateIsClass(subtypeVar, classGenerator, tagRegistry, className, function.getBody());
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
ValueType itemType = ((ValueType.Array) type).getItemType();
|
||||
generateIsArray(subtypeVar, classGenerator, itemType, function.getBody());
|
||||
generateIsArray(subtypeVar, classGenerator, functions, itemType, function.getBody());
|
||||
} else {
|
||||
int expected = classGenerator.getClassPointer(type);
|
||||
WasmExpression condition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ,
|
||||
|
@ -971,8 +969,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
body.add(new WasmReturn(new WasmInt32Constant(1)));
|
||||
}
|
||||
|
||||
private void generateIsArray(WasmLocal subtypeVar, WasmClassGenerator classGenerator, ValueType itemType,
|
||||
List<WasmExpression> body) {
|
||||
private void generateIsArray(WasmLocal subtypeVar, WasmClassGenerator classGenerator,
|
||||
WasmFunctionRepository functions, ValueType itemType, List<WasmExpression> body) {
|
||||
int itemOffset = classGenerator.getFieldOffset(new FieldReference(RuntimeClass.class.getName(), "itemType"));
|
||||
|
||||
var itemExpression = new WasmLoadInt32(4, new WasmGetLocal(subtypeVar), WasmInt32Subtype.INT32);
|
||||
|
@ -984,18 +982,18 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
itemTest.setType(WasmType.INT32);
|
||||
itemTest.getThenBlock().getBody().add(new WasmInt32Constant(0));
|
||||
|
||||
WasmCall delegateToItem = new WasmCall(classGenerator.names.forSupertypeFunction(itemType));
|
||||
WasmCall delegateToItem = new WasmCall(functions.forSupertype(itemType));
|
||||
delegateToItem.getArguments().add(new WasmGetLocal(subtypeVar));
|
||||
itemTest.getElseBlock().getBody().add(delegateToItem);
|
||||
|
||||
body.add(new WasmReturn(itemTest));
|
||||
}
|
||||
|
||||
private void generateStub(NameProvider names, WasmModule module, MethodHolder method, MethodHolder implementor) {
|
||||
WasmFunction function = module.getFunctions().get(names.forMethod(method.getReference()));
|
||||
private void generateStub(WasmFunctionRepository functions, MethodHolder method, MethodHolder implementor) {
|
||||
WasmFunction function = functions.forMethod(method);
|
||||
|
||||
WasmCall call = new WasmCall(names.forMethod(implementor.getReference()));
|
||||
for (WasmType param : function.getParameters()) {
|
||||
WasmCall call = new WasmCall(functions.forMethod(implementor));
|
||||
for (WasmType param : function.getType().getParameterTypes()) {
|
||||
WasmLocal local = new WasmLocal(param);
|
||||
function.add(local);
|
||||
call.getArguments().add(new WasmGetLocal(local));
|
||||
|
@ -1009,7 +1007,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
}
|
||||
|
||||
private void renderClinit(ListableClassReaderSource classes, WasmClassGenerator classGenerator,
|
||||
WasmModule module) {
|
||||
WasmFunctionRepository functions) {
|
||||
for (ValueType type : classGenerator.getRegisteredClasses()) {
|
||||
if (!(type instanceof ValueType.Object)) {
|
||||
continue;
|
||||
|
@ -1028,8 +1026,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
continue;
|
||||
}
|
||||
|
||||
WasmFunction initFunction = new WasmFunction(classGenerator.names.forClassInitializer(className));
|
||||
module.add(initFunction);
|
||||
var initFunction = functions.forClassInitializer(className);
|
||||
|
||||
WasmBlock block = new WasmBlock(false);
|
||||
|
||||
|
@ -1047,7 +1044,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
block.getBody().add(new WasmStoreInt32(4, new WasmInt32Constant(index), initFlag,
|
||||
WasmInt32Subtype.INT32));
|
||||
|
||||
block.getBody().add(new WasmCall(classGenerator.names.forMethod(method.getReference())));
|
||||
block.getBody().add(new WasmCall(functions.forMethod(method)));
|
||||
|
||||
if (controller.wasCancelled()) {
|
||||
break;
|
||||
|
@ -1129,17 +1126,18 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
private BinaryWriter binaryWriter;
|
||||
private WasmStringPool stringPool;
|
||||
private Diagnostics diagnostics;
|
||||
private NameProvider names;
|
||||
private WasmFunctionRepository functions;
|
||||
private WasmClassGenerator classGenerator;
|
||||
private ClassReaderSource classSource;
|
||||
|
||||
MethodGeneratorContextImpl(BinaryWriter binaryWriter, WasmStringPool stringPool,
|
||||
Diagnostics diagnostics, NameProvider names, WasmClassGenerator classGenerator,
|
||||
Diagnostics diagnostics, WasmFunctionRepository functions,
|
||||
WasmClassGenerator classGenerator,
|
||||
ClassReaderSource classSource) {
|
||||
this.binaryWriter = binaryWriter;
|
||||
this.stringPool = stringPool;
|
||||
this.diagnostics = diagnostics;
|
||||
this.names = names;
|
||||
this.functions = functions;
|
||||
this.classGenerator = classGenerator;
|
||||
this.classSource = classSource;
|
||||
}
|
||||
|
@ -1159,9 +1157,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
return diagnostics;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NameProvider getNames() {
|
||||
return names;
|
||||
public WasmFunctionRepository getFunctions() {
|
||||
return functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1197,8 +1196,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
case "runMain": {
|
||||
var entryPoint = new MethodReference(controller.getEntryPoint(),
|
||||
"main", ValueType.parse(String[].class), ValueType.parse(void.class));
|
||||
String name = manager.getNames().forMethod(entryPoint);
|
||||
WasmCall call = new WasmCall(name);
|
||||
var function = manager.getFunctions().forStaticMethod(entryPoint);
|
||||
WasmCall call = new WasmCall(function);
|
||||
var arg = manager.generate(invocation.getArguments().get(0));
|
||||
if (manager.isManagedMethodCall(entryPoint)) {
|
||||
var block = new WasmBlock(false);
|
||||
|
@ -1214,9 +1213,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
|
|||
return call;
|
||||
}
|
||||
case "setCurrentThread": {
|
||||
String name = manager.getNames().forMethod(new MethodReference(Thread.class,
|
||||
var function = manager.getFunctions().forStaticMethod(new MethodReference(Thread.class,
|
||||
"setCurrentThread", Thread.class, void.class));
|
||||
WasmCall call = new WasmCall(name);
|
||||
WasmCall call = new WasmCall(function);
|
||||
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
|
||||
call.setLocation(invocation.getLocation());
|
||||
return call;
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
|||
import java.io.PrintWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||
|
@ -103,7 +104,8 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
|||
|
||||
private String typeToString(WasmType type) {
|
||||
if (type != null) {
|
||||
switch (type) {
|
||||
if (type instanceof WasmType.Number) {
|
||||
switch (((WasmType.Number) type).number) {
|
||||
case INT32:
|
||||
return "i32";
|
||||
case INT64:
|
||||
|
@ -115,6 +117,9 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
|||
default:
|
||||
break;
|
||||
}
|
||||
} else if (type instanceof WasmType.Reference) {
|
||||
return "ref";
|
||||
}
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
@ -615,7 +620,7 @@ public class DisassemblyCodeSectionListener implements AddressListener, CodeSect
|
|||
}
|
||||
|
||||
@Override
|
||||
public void convert(WasmType sourceType, WasmType targetType, boolean signed, boolean reinterpret) {
|
||||
public void convert(WasmNumType sourceType, WasmNumType targetType, boolean signed, boolean reinterpret) {
|
||||
switch (targetType) {
|
||||
case INT32:
|
||||
writer.write("i32.");
|
||||
|
|
|
@ -16,27 +16,23 @@
|
|||
package org.teavm.backend.wasm.generate;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
||||
class TemporaryVariablePool {
|
||||
private WasmFunction function;
|
||||
private List<Deque<WasmLocal>> temporaryVariablesByType = new ArrayList<>();
|
||||
private Map<WasmType, Deque<WasmLocal>> temporaryVariablesByType = new HashMap<>();
|
||||
|
||||
TemporaryVariablePool(WasmFunction function) {
|
||||
this.function = function;
|
||||
int typeCount = WasmType.values().length;
|
||||
for (int i = 0; i < typeCount; ++i) {
|
||||
temporaryVariablesByType.add(new ArrayDeque<>());
|
||||
}
|
||||
}
|
||||
|
||||
WasmLocal acquire(WasmType type) {
|
||||
var stack = temporaryVariablesByType.get(type.ordinal());
|
||||
var stack = temporaryVariablesByType.computeIfAbsent(type, k -> new ArrayDeque<>());
|
||||
WasmLocal variable = stack.pollFirst();
|
||||
if (variable == null) {
|
||||
variable = new WasmLocal(type);
|
||||
|
@ -46,7 +42,7 @@ class TemporaryVariablePool {
|
|||
}
|
||||
|
||||
void release(WasmLocal variable) {
|
||||
var stack = temporaryVariablesByType.get(variable.getType().ordinal());
|
||||
var stack = temporaryVariablesByType.get(variable.getType());
|
||||
stack.push(variable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
import org.teavm.backend.wasm.binary.DataArray;
|
||||
import org.teavm.backend.wasm.binary.DataPrimitives;
|
||||
|
@ -33,6 +33,8 @@ import org.teavm.backend.wasm.binary.DataType;
|
|||
import org.teavm.backend.wasm.binary.DataValue;
|
||||
import org.teavm.backend.wasm.debug.DebugClassLayout;
|
||||
import org.teavm.backend.wasm.debug.info.FieldType;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
|
||||
import org.teavm.common.IntegerArray;
|
||||
import org.teavm.interop.Address;
|
||||
|
@ -60,12 +62,12 @@ public class WasmClassGenerator {
|
|||
private ClassReaderSource processedClassSource;
|
||||
private ClassReaderSource classSource;
|
||||
private Characteristics characteristics;
|
||||
public final NameProvider names;
|
||||
public final WasmFunctionRepository functions;
|
||||
public final WasmModule module;
|
||||
private Map<ValueType, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
||||
private BinaryWriter binaryWriter;
|
||||
private Map<MethodReference, Integer> functions = new HashMap<>();
|
||||
private List<String> functionTable = new ArrayList<>();
|
||||
private ObjectIntMap<String> functionIdMap = new ObjectIntHashMap<>();
|
||||
private Map<MethodReference, Integer> tableFunctions = new HashMap<>();
|
||||
private ObjectIntMap<WasmFunction> functionIdMap = new ObjectIntHashMap<>();
|
||||
private VirtualTableProvider vtableProvider;
|
||||
private TagRegistry tagRegistry;
|
||||
private WasmStringPool stringPool;
|
||||
|
@ -122,7 +124,7 @@ public class WasmClassGenerator {
|
|||
|
||||
public WasmClassGenerator(ClassReaderSource processedClassSource, ClassReaderSource classSource,
|
||||
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter,
|
||||
NameProvider names, ClassMetadataRequirements metadataRequirements,
|
||||
WasmFunctionRepository functions, WasmModule module, ClassMetadataRequirements metadataRequirements,
|
||||
ClassInitializerInfo classInitializerInfo, Characteristics characteristics,
|
||||
DwarfClassGenerator dwarfClassGenerator, WasmBinaryStatsCollector statsCollector) {
|
||||
this.processedClassSource = processedClassSource;
|
||||
|
@ -130,8 +132,9 @@ public class WasmClassGenerator {
|
|||
this.vtableProvider = vtableProvider;
|
||||
this.tagRegistry = tagRegistry;
|
||||
this.binaryWriter = binaryWriter;
|
||||
this.functions = functions;
|
||||
this.module = module;
|
||||
this.stringPool = new WasmStringPool(this, binaryWriter, statsCollector);
|
||||
this.names = names;
|
||||
this.metadataRequirements = metadataRequirements;
|
||||
this.classInitializerInfo = classInitializerInfo;
|
||||
this.characteristics = characteristics;
|
||||
|
@ -223,7 +226,7 @@ public class WasmClassGenerator {
|
|||
binaryData.data = wrapper.getValue(0);
|
||||
binaryData.data.setInt(CLASS_SIZE, 4);
|
||||
binaryData.data.setAddress(CLASS_ITEM_TYPE, itemBinaryData.start);
|
||||
binaryData.data.setInt(CLASS_IS_INSTANCE, getFunctionPointer(names.forSupertypeFunction(type)));
|
||||
binaryData.data.setInt(CLASS_IS_INSTANCE, getFunctionPointer(functions.forSupertype(type)));
|
||||
binaryData.data.setInt(CLASS_CANARY, RuntimeClass.computeCanary(4, 0));
|
||||
binaryData.data.setAddress(CLASS_NAME, stringPool.getStringPointer(type.toString().replace('/', '.')));
|
||||
binaryData.data.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||
|
@ -238,7 +241,7 @@ public class WasmClassGenerator {
|
|||
private DataValue createPrimitiveClassData(DataValue value, int size, ValueType type) {
|
||||
value.setInt(CLASS_SIZE, size);
|
||||
value.setInt(CLASS_FLAGS, RuntimeClass.PRIMITIVE);
|
||||
value.setInt(CLASS_IS_INSTANCE, getFunctionPointer(names.forSupertypeFunction(type)));
|
||||
value.setInt(CLASS_IS_INSTANCE, getFunctionPointer(functions.forSupertype(type)));
|
||||
value.setAddress(CLASS_SIMPLE_NAME, 0);
|
||||
value.setInt(CLASS_INIT, -1);
|
||||
value.setInt(CLASS_TAG, Integer.MAX_VALUE);
|
||||
|
@ -282,16 +285,12 @@ public class WasmClassGenerator {
|
|||
return value;
|
||||
}
|
||||
|
||||
public Iterable<? extends String> getFunctionTable() {
|
||||
return functionTable;
|
||||
}
|
||||
|
||||
public int getFunctionPointer(String name) {
|
||||
var result = functionIdMap.getOrDefault(name, -1);
|
||||
public int getFunctionPointer(WasmFunction function) {
|
||||
var result = functionIdMap.getOrDefault(function, -1);
|
||||
if (result < 0) {
|
||||
result = functionTable.size();
|
||||
functionTable.add(name);
|
||||
functionIdMap.put(name, result);
|
||||
result = module.getFunctionTable().size();
|
||||
module.getFunctionTable().add(function);
|
||||
functionIdMap.put(function, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -326,7 +325,7 @@ public class WasmClassGenerator {
|
|||
header.setInt(CLASS_CANARY, RuntimeClass.computeCanary(occupiedSize, tag));
|
||||
int nameAddress = requirements.name() ? stringPool.getStringPointer(name) : 0;
|
||||
header.setAddress(CLASS_NAME, nameAddress);
|
||||
header.setInt(CLASS_IS_INSTANCE, getFunctionPointer(names.forSupertypeFunction(ValueType.object(name))));
|
||||
header.setInt(CLASS_IS_INSTANCE, getFunctionPointer(functions.forSupertype(ValueType.object(name))));
|
||||
header.setAddress(CLASS_PARENT, parentPtr);
|
||||
|
||||
ClassReader cls = processedClassSource.get(name);
|
||||
|
@ -381,7 +380,7 @@ public class WasmClassGenerator {
|
|||
if (cls != null && binaryData.start >= 0
|
||||
&& cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null
|
||||
&& classInitializerInfo.isDynamicInitializer(name)) {
|
||||
header.setInt(CLASS_INIT, getFunctionPointer(names.forClassInitializer(name)));
|
||||
header.setInt(CLASS_INIT, getFunctionPointer(functions.forClassInitializer(name)));
|
||||
} else {
|
||||
header.setInt(CLASS_INIT, -1);
|
||||
}
|
||||
|
@ -458,8 +457,8 @@ public class WasmClassGenerator {
|
|||
if (method != null) {
|
||||
VirtualTableEntry entry = vtable.getEntry(method);
|
||||
if (entry != null) {
|
||||
methodIndex = functions.computeIfAbsent(entry.getImplementor(),
|
||||
implementor -> getFunctionPointer(names.forMethod(implementor)));
|
||||
methodIndex = tableFunctions.computeIfAbsent(entry.getImplementor(),
|
||||
implementor -> getFunctionPointer(functions.forInstanceMethod(implementor)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,10 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.generators.WasmMethodGenerator;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmTag;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
|
@ -43,7 +44,9 @@ import org.teavm.model.lowlevel.Characteristics;
|
|||
|
||||
public class WasmGenerationContext {
|
||||
private ClassReaderSource classSource;
|
||||
private WasmModule module;
|
||||
public final WasmModule module;
|
||||
public final WasmFunctionTypes functionTypes;
|
||||
public final WasmFunctionRepository functions;
|
||||
private Diagnostics diagnostics;
|
||||
private VirtualTableProvider vtableProvider;
|
||||
private TagRegistry tagRegistry;
|
||||
|
@ -58,11 +61,14 @@ public class WasmGenerationContext {
|
|||
private WasmTag exceptionTag;
|
||||
public final List<CallSiteDescriptor> callSites = new ArrayList<>();
|
||||
|
||||
public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, Diagnostics diagnostics,
|
||||
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool,
|
||||
NameProvider names, Characteristics characteristics, WasmTag exceptionTag) {
|
||||
public WasmGenerationContext(ClassReaderSource classSource, WasmModule module, WasmFunctionTypes functionTypes,
|
||||
WasmFunctionRepository functions, Diagnostics diagnostics, VirtualTableProvider vtableProvider,
|
||||
TagRegistry tagRegistry, WasmStringPool stringPool, NameProvider names, Characteristics characteristics,
|
||||
WasmTag exceptionTag) {
|
||||
this.classSource = classSource;
|
||||
this.module = module;
|
||||
this.functionTypes = functionTypes;
|
||||
this.functions = functions;
|
||||
this.diagnostics = diagnostics;
|
||||
this.vtableProvider = vtableProvider;
|
||||
this.tagRegistry = tagRegistry;
|
||||
|
@ -135,10 +141,6 @@ public class WasmGenerationContext {
|
|||
});
|
||||
}
|
||||
|
||||
public WasmFunction getFunction(String name) {
|
||||
return module.getFunctions().get(name);
|
||||
}
|
||||
|
||||
public ClassReaderSource getClassSource() {
|
||||
return classSource;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,8 @@ import org.teavm.ast.UnaryExpr;
|
|||
import org.teavm.ast.UnwrapArrayExpr;
|
||||
import org.teavm.ast.VariableExpr;
|
||||
import org.teavm.ast.WhileStatement;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.WasmHeap;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
|
@ -74,6 +75,7 @@ import org.teavm.backend.wasm.binary.DataPrimitives;
|
|||
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmTag;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
|
@ -196,12 +198,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
this.firstVariable = firstVariable;
|
||||
tempVars = new TemporaryVariablePool(function);
|
||||
exprCache = new ExpressionCache(tempVars);
|
||||
typeInference = new WasmTypeInference(context);
|
||||
typeInference = new WasmTypeInference();
|
||||
this.async = async;
|
||||
this.managed = context.characteristics.isManaged(currentMethod);
|
||||
}
|
||||
|
||||
|
||||
void generate(Statement statement, List<WasmExpression> target) {
|
||||
var lastTargetSize = target.size();
|
||||
resultConsumer = target;
|
||||
|
@ -212,7 +213,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
rethrowBlock.getBody().addAll(body);
|
||||
body.clear();
|
||||
target.add(rethrowBlock);
|
||||
var valueToReturn = WasmExpression.defaultValueOfType(function.getResult());
|
||||
var valueToReturn = WasmExpression.defaultValueOfType(function.getType().getReturnType());
|
||||
if (valueToReturn != null) {
|
||||
target.add(new WasmReturn(valueToReturn));
|
||||
}
|
||||
|
@ -254,7 +255,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
default:
|
||||
Class<?> type = convertType(expr.getType());
|
||||
MethodReference method = new MethodReference(WasmRuntime.class, "remainder", type, type, type);
|
||||
WasmCall call = new WasmCall(context.names.forMethod(method), false);
|
||||
WasmCall call = new WasmCall(context.functions.forStaticMethod(method));
|
||||
|
||||
accept(expr.getFirstOperand());
|
||||
call.getArguments().add(result);
|
||||
|
@ -308,7 +309,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
case COMPARE: {
|
||||
Class<?> type = convertType(expr.getType());
|
||||
MethodReference method = new MethodReference(WasmRuntime.class, "compare", type, type, int.class);
|
||||
WasmCall call = new WasmCall(context.names.forMethod(method), false);
|
||||
var call = new WasmCall(context.functions.forStaticMethod(method));
|
||||
|
||||
accept(expr.getFirstOperand());
|
||||
call.getArguments().add(result);
|
||||
|
@ -367,7 +368,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
case LEFT_SHIFT:
|
||||
case RIGHT_SHIFT:
|
||||
case UNSIGNED_RIGHT_SHIFT:
|
||||
second = new WasmConversion(WasmType.INT32, WasmType.INT64, false, second);
|
||||
second = new WasmConversion(WasmNumType.INT32, WasmNumType.INT64, false, second);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -529,7 +530,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
var callSiteId = generateCallSiteId(location);
|
||||
block.getBody().add(generateRegisterCallSite(callSiteId, location));
|
||||
|
||||
var call = new WasmCall(context.names.forMethod(THROW_NPE_METHOD));
|
||||
var call = new WasmCall(context.functions.forStaticMethod(THROW_NPE_METHOD));
|
||||
block.getBody().add(call);
|
||||
|
||||
if (context.getExceptionTag() == null) {
|
||||
|
@ -1155,12 +1156,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) {
|
||||
MethodReader method = context.getClassSource().resolve(expr.getMethod());
|
||||
MethodReference reference = method != null ? method.getReference() : expr.getMethod();
|
||||
String methodName = context.names.forMethod(reference);
|
||||
var function = context.functions.forMethod(reference, expr.getType() == InvocationType.STATIC);
|
||||
|
||||
WasmCall call = new WasmCall(methodName);
|
||||
if (context.getImportedMethod(reference) != null) {
|
||||
call.setImported(true);
|
||||
}
|
||||
var call = new WasmCall(function);
|
||||
for (Expr argument : expr.getArguments()) {
|
||||
accept(argument);
|
||||
call.getArguments().add(result);
|
||||
|
@ -1179,8 +1177,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
block.getBody().add(new WasmSetLocal(tmp, allocateObject(expr.getMethod().getClassName(),
|
||||
expr.getLocation())));
|
||||
|
||||
String methodName = context.names.forMethod(expr.getMethod());
|
||||
WasmCall call = new WasmCall(methodName);
|
||||
var function = context.functions.forInstanceMethod(expr.getMethod());
|
||||
var call = new WasmCall(function);
|
||||
call.getArguments().add(new WasmGetLocal(tmp));
|
||||
for (Expr argument : expr.getArguments()) {
|
||||
accept(argument);
|
||||
|
@ -1220,14 +1218,14 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
var methodIndex = new WasmLoadInt32(4, classRef, WasmInt32Subtype.INT32);
|
||||
methodIndex.setOffset(vtableIndex * 4 + vtableOffset);
|
||||
|
||||
WasmIndirectCall call = new WasmIndirectCall(methodIndex);
|
||||
call.getParameterTypes().add(WasmType.INT32);
|
||||
for (int i = 0; i < expr.getMethod().parameterCount(); ++i) {
|
||||
call.getParameterTypes().add(WasmGeneratorUtil.mapType(expr.getMethod().parameterType(i)));
|
||||
}
|
||||
if (expr.getMethod().getReturnType() != ValueType.VOID) {
|
||||
call.setReturnType(WasmGeneratorUtil.mapType(expr.getMethod().getReturnType()));
|
||||
var parameterTypes = new WasmType[expr.getMethod().parameterCount() + 1];
|
||||
parameterTypes[0] = WasmType.INT32;
|
||||
for (var i = 0; i < expr.getMethod().parameterCount(); ++i) {
|
||||
parameterTypes[i + 1] = WasmGeneratorUtil.mapType(expr.getMethod().parameterType(i));
|
||||
}
|
||||
var functionType = context.functionTypes.of(WasmGeneratorUtil.mapType(expr.getMethod().getReturnType()),
|
||||
parameterTypes);
|
||||
var call = new WasmIndirectCall(methodIndex, functionType);
|
||||
|
||||
call.getArguments().add(instance);
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
|
@ -1267,7 +1265,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
stackVariable = tempVars.acquire(WasmType.INT32);
|
||||
stackVariable.setName("__stack__");
|
||||
InvocationExpr expr = new InvocationExpr();
|
||||
expr.setType(InvocationType.SPECIAL);
|
||||
expr.setType(InvocationType.STATIC);
|
||||
expr.setMethod(new MethodReference(WasmRuntime.class, "allocStack", int.class, Address.class));
|
||||
expr.getArguments().add(sizeExpr);
|
||||
expr.acceptVisitor(this);
|
||||
|
@ -1506,9 +1504,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
private WasmExpression allocateObject(String className, TextLocation location) {
|
||||
int tag = classGenerator.getClassPointer(ValueType.object(className));
|
||||
String allocName = context.names.forMethod(new MethodReference(Allocator.class, "allocate",
|
||||
var allocFunction = context.functions.forStaticMethod(new MethodReference(Allocator.class, "allocate",
|
||||
RuntimeClass.class, Address.class));
|
||||
WasmCall call = new WasmCall(allocName);
|
||||
WasmCall call = new WasmCall(allocFunction);
|
||||
call.getArguments().add(new WasmInt32Constant(tag));
|
||||
call.setLocation(location);
|
||||
return call;
|
||||
|
@ -1525,9 +1523,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
ValueType type = expr.getType();
|
||||
|
||||
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type));
|
||||
String allocName = context.names.forMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||
var allocFunction = context.functions.forStaticMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||
RuntimeClass.class, int.class, Address.class));
|
||||
WasmCall call = new WasmCall(allocName);
|
||||
var call = new WasmCall(allocFunction);
|
||||
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||
accept(expr.getLength());
|
||||
call.getArguments().add(result);
|
||||
|
@ -1576,9 +1574,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
WasmLocal array = tempVars.acquire(WasmType.INT32);
|
||||
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type));
|
||||
String allocName = context.names.forMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||
var allocFunction = context.functions.forStaticMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||
RuntimeClass.class, int.class, Address.class));
|
||||
WasmCall call = new WasmCall(allocName);
|
||||
WasmCall call = new WasmCall(allocFunction);
|
||||
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||
call.getArguments().add(new WasmInt32Constant(expr.getData().size()));
|
||||
call.setLocation(expr.getLocation());
|
||||
|
@ -1616,9 +1614,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
int classPointer = classGenerator.getClassPointer(type);
|
||||
String allocName = context.names.forMethod(new MethodReference(Allocator.class, "allocateMultiArray",
|
||||
var allocFunction = context.functions.forStaticMethod(new MethodReference(Allocator.class, "allocateMultiArray",
|
||||
RuntimeClass.class, Address.class, int.class, RuntimeArray.class));
|
||||
WasmCall call = new WasmCall(allocName);
|
||||
var call = new WasmCall(allocFunction);
|
||||
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||
call.getArguments().add(new WasmInt32Constant(dimensionList));
|
||||
call.getArguments().add(new WasmInt32Constant(expr.getDimensions().size()));
|
||||
|
@ -1673,7 +1671,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
private WasmExpression instanceOfImpl(WasmExpression expression, ValueType type) {
|
||||
WasmCall supertypeCall = new WasmCall(context.names.forSupertypeFunction(type));
|
||||
var supertypeCall = new WasmCall(context.functions.forSupertype(type));
|
||||
WasmExpression classRef = new WasmLoadInt32(4, expression, WasmInt32Subtype.INT32);
|
||||
classRef = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classRef,
|
||||
new WasmInt32Constant(3));
|
||||
|
@ -1687,7 +1685,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
resultConsumer.add(generateRegisterCallSite(callSiteId, statement.getLocation()));
|
||||
|
||||
accept(statement.getException());
|
||||
var call = new WasmCall(context.names.forMethod(THROW_METHOD), result);
|
||||
var call = new WasmCall(context.functions.forStaticMethod(THROW_METHOD), result);
|
||||
call.setLocation(statement.getLocation());
|
||||
resultConsumer.add(call);
|
||||
|
||||
|
@ -1728,7 +1726,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
nullCheck.setResult(valueToCast.expr());
|
||||
block.getBody().add(new WasmDrop(nullCheck));
|
||||
|
||||
var supertypeCall = new WasmCall(context.names.forSupertypeFunction(expr.getTarget()));
|
||||
var supertypeCall = new WasmCall(context.functions.forSupertype(expr.getTarget()));
|
||||
WasmExpression classRef = new WasmLoadInt32(4, valueToCast.expr(), WasmInt32Subtype.INT32);
|
||||
classRef = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classRef,
|
||||
new WasmInt32Constant(3));
|
||||
|
@ -1741,7 +1739,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
var callSiteId = generateCallSiteId(expr.getLocation());
|
||||
block.getBody().add(generateRegisterCallSite(callSiteId, expr.getLocation()));
|
||||
|
||||
var call = new WasmCall(context.names.forMethod(THROW_CCE_METHOD));
|
||||
var call = new WasmCall(context.functions.forStaticMethod(THROW_CCE_METHOD));
|
||||
block.getBody().add(call);
|
||||
|
||||
if (context.getExceptionTag() == null) {
|
||||
|
@ -1762,7 +1760,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
@Override
|
||||
public void visit(InitClassStatement statement) {
|
||||
if (classGenerator.hasClinit(statement.getClassName())) {
|
||||
var call = new WasmCall(context.names.forClassInitializer(statement.getClassName()));
|
||||
var call = new WasmCall(context.functions.forClassInitializer(statement.getClassName()));
|
||||
call.setLocation(statement.getLocation());
|
||||
|
||||
var callSiteId = generateCallSiteId(statement.getLocation());
|
||||
|
@ -1853,8 +1851,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
var tryCatch = tryCatchStatements.get(i);
|
||||
var catchBlock = catchBlocks.get(i);
|
||||
catchBlock.getBody().add(currentBlock);
|
||||
var catchMethodName = context.names.forMethod(CATCH_METHOD);
|
||||
var catchCall = new WasmCall(catchMethodName);
|
||||
var catchFunction = context.functions.forStaticMethod(CATCH_METHOD);
|
||||
var catchCall = new WasmCall(catchFunction);
|
||||
var catchWrapper = tryCatch.getExceptionVariable() != null
|
||||
? new WasmSetLocal(localVar(tryCatch.getExceptionVariable()), catchCall)
|
||||
: new WasmDrop(catchCall);
|
||||
|
@ -1887,8 +1885,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
tryBlock.getCatches().add(catchClause);
|
||||
innerCatchBlock.getBody().add(tryBlock);
|
||||
|
||||
var obj = exprCache.create(new WasmCall(context.names.forMethod(PEEK_EXCEPTION_METHOD)), WasmType.INT32,
|
||||
null, innerCatchBlock.getBody());
|
||||
var obj = exprCache.create(new WasmCall(context.functions.forStaticMethod(PEEK_EXCEPTION_METHOD)),
|
||||
WasmType.INT32, null, innerCatchBlock.getBody());
|
||||
var currentBlock = innerCatchBlock;
|
||||
boolean catchesAll = false;
|
||||
for (int i = tryCatchStatements.size() - 1; i >= 0; --i) {
|
||||
|
@ -1916,8 +1914,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
var catchBlock = catchBlocks.get(i);
|
||||
catchBlock.getBody().add(currentBlock);
|
||||
|
||||
var catchMethodName = context.names.forMethod(CATCH_METHOD);
|
||||
var catchCall = new WasmCall(catchMethodName);
|
||||
var catchFunction = context.functions.forStaticMethod(CATCH_METHOD);
|
||||
var catchCall = new WasmCall(catchFunction);
|
||||
var catchWrapper = tryCatch.getExceptionVariable() != null
|
||||
? new WasmSetLocal(localVar(tryCatch.getExceptionVariable()), catchCall)
|
||||
: new WasmDrop(catchCall);
|
||||
|
@ -1954,7 +1952,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
WasmCall call = new WasmCall(context.names.forMethod(async ? MONITOR_ENTER : MONITOR_ENTER_SYNC));
|
||||
var call = new WasmCall(context.functions.forStaticMethod(async ? MONITOR_ENTER : MONITOR_ENTER_SYNC));
|
||||
call.setLocation(statement.getLocation());
|
||||
statement.getObjectRef().acceptVisitor(this);
|
||||
call.getArguments().add(result);
|
||||
|
@ -1967,7 +1965,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
var call = new WasmCall(context.names.forMethod(async ? MONITOR_EXIT : MONITOR_EXIT_SYNC));
|
||||
var call = new WasmCall(context.functions.forStaticMethod(async ? MONITOR_EXIT : MONITOR_EXIT_SYNC));
|
||||
call.setLocation(statement.getLocation());
|
||||
statement.getObjectRef().acceptVisitor(this);
|
||||
call.getArguments().add(result);
|
||||
|
@ -2021,7 +2019,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
var callSiteId = generateCallSiteId(expr.getLocation());
|
||||
block.getBody().add(generateRegisterCallSite(callSiteId, expr.getLocation()));
|
||||
block.getBody().add(new WasmCall(context.names.forMethod(THROW_AIOOBE_METHOD)));
|
||||
block.getBody().add(new WasmCall(context.functions.forStaticMethod(THROW_AIOOBE_METHOD)));
|
||||
if (context.getExceptionTag() == null) {
|
||||
var br = new WasmBreak(throwJumpTarget());
|
||||
if (br.getTarget() != rethrowBlock) {
|
||||
|
@ -2213,8 +2211,13 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NameProvider getNames() {
|
||||
return context.names;
|
||||
public WasmFunctionRepository getFunctions() {
|
||||
return context.functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmFunctionTypes getFunctionTypes() {
|
||||
return context.functionTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2238,8 +2241,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getFunctionPointer(String name) {
|
||||
return classGenerator.getFunctionPointer(name);
|
||||
public int getFunctionPointer(WasmFunction function) {
|
||||
return classGenerator.getFunctionPointer(function);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,12 +19,10 @@ import java.util.function.Predicate;
|
|||
import org.teavm.ast.RegularMethodNode;
|
||||
import org.teavm.ast.VariableNode;
|
||||
import org.teavm.ast.decompilation.Decompiler;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
import org.teavm.backend.wasm.debug.info.VariableType;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmTag;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.interop.Export;
|
||||
import org.teavm.model.AnnotationReader;
|
||||
|
@ -32,8 +30,8 @@ import org.teavm.model.ClassHolder;
|
|||
import org.teavm.model.ClassHolderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmGenerator {
|
||||
private Decompiler decompiler;
|
||||
|
@ -41,9 +39,7 @@ public class WasmGenerator {
|
|||
private WasmGenerationContext context;
|
||||
private WasmClassGenerator classGenerator;
|
||||
private BinaryWriter binaryWriter;
|
||||
private NameProvider names;
|
||||
private Predicate<MethodReference> asyncMethods;
|
||||
private WasmTag exceptionTag;
|
||||
|
||||
public WasmGenerator(Decompiler decompiler, ClassHolderSource classSource,
|
||||
WasmGenerationContext context, WasmClassGenerator classGenerator, BinaryWriter binaryWriter,
|
||||
|
@ -53,35 +49,15 @@ public class WasmGenerator {
|
|||
this.context = context;
|
||||
this.classGenerator = classGenerator;
|
||||
this.binaryWriter = binaryWriter;
|
||||
names = classGenerator.names;
|
||||
this.asyncMethods = asyncMethods;
|
||||
}
|
||||
|
||||
public WasmFunction generateDefinition(MethodReference methodReference) {
|
||||
ClassHolder cls = classSource.get(methodReference.getClassName());
|
||||
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
|
||||
WasmFunction function = new WasmFunction(names.forMethod(method.getReference()));
|
||||
function.setJavaMethod(methodReference);
|
||||
|
||||
if (!method.hasModifier(ElementModifier.STATIC)) {
|
||||
function.getParameters().add(WasmType.INT32);
|
||||
}
|
||||
for (int i = 0; i < method.parameterCount(); ++i) {
|
||||
function.getParameters().add(WasmGeneratorUtil.mapType(method.parameterType(i)));
|
||||
}
|
||||
if (method.getResultType() != ValueType.VOID) {
|
||||
function.setResult(WasmGeneratorUtil.mapType(method.getResultType()));
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
public WasmFunction generate(MethodReference methodReference, MethodHolder bodyMethod) {
|
||||
ClassHolder cls = classSource.get(methodReference.getClassName());
|
||||
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
|
||||
|
||||
RegularMethodNode methodAst = decompiler.decompileRegular(bodyMethod);
|
||||
WasmFunction function = context.getFunction(names.forMethod(methodReference));
|
||||
WasmFunction function = context.functions.forMethod(method);
|
||||
int firstVariable = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
|
||||
for (int i = firstVariable; i < methodAst.getVariables().size(); ++i) {
|
||||
VariableNode variable = methodAst.getVariables().get(i);
|
||||
|
@ -120,10 +96,10 @@ public class WasmGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
public WasmFunction generateNative(MethodReference methodReference) {
|
||||
WasmFunction function = context.getFunction(names.forMethod(methodReference));
|
||||
public WasmFunction generateNative(MethodReader method) {
|
||||
var function = context.functions.forMethod(method);
|
||||
|
||||
WasmGenerationContext.ImportedMethod importedMethod = context.getImportedMethod(methodReference);
|
||||
var importedMethod = context.getImportedMethod(method.getReference());
|
||||
if (importedMethod != null) {
|
||||
function.setImportName(importedMethod.name);
|
||||
function.setImportModule(importedMethod.module);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.backend.wasm.generate;
|
||||
|
||||
import org.teavm.ast.OperationType;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.util.VariableType;
|
||||
|
@ -24,16 +25,16 @@ public final class WasmGeneratorUtil {
|
|||
private WasmGeneratorUtil() {
|
||||
}
|
||||
|
||||
public static WasmType mapType(OperationType type) {
|
||||
public static WasmNumType mapType(OperationType type) {
|
||||
switch (type) {
|
||||
case INT:
|
||||
return WasmType.INT32;
|
||||
return WasmNumType.INT32;
|
||||
case LONG:
|
||||
return WasmType.INT64;
|
||||
return WasmNumType.INT64;
|
||||
case FLOAT:
|
||||
return WasmType.FLOAT32;
|
||||
return WasmNumType.FLOAT32;
|
||||
case DOUBLE:
|
||||
return WasmType.FLOAT64;
|
||||
return WasmNumType.FLOAT64;
|
||||
}
|
||||
throw new IllegalArgumentException(type.toString());
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.generate;
|
||||
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
|
@ -39,48 +40,49 @@ import org.teavm.runtime.RuntimeClass;
|
|||
|
||||
public class WasmInteropFunctionGenerator {
|
||||
private WasmClassGenerator classGenerator;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
|
||||
public WasmInteropFunctionGenerator(WasmClassGenerator classGenerator) {
|
||||
public WasmInteropFunctionGenerator(WasmClassGenerator classGenerator, WasmFunctionTypes functionTypes) {
|
||||
this.classGenerator = classGenerator;
|
||||
this.functionTypes = functionTypes;
|
||||
}
|
||||
|
||||
public void generateFunctions(WasmModule module) {
|
||||
module.add(allocateString());
|
||||
module.add(stringData());
|
||||
module.functions.add(allocateString());
|
||||
module.functions.add(stringData());
|
||||
|
||||
module.add(allocateArray("teavm_allocateObjectArray", ValueType.parse(Object.class)));
|
||||
module.add(allocateArray("teavm_allocateStringArray", ValueType.parse(String.class)));
|
||||
module.add(allocateArray("teavm_allocateByteArray", ValueType.parse(byte.class)));
|
||||
module.add(allocateArray("teavm_allocateShortArray", ValueType.parse(short.class)));
|
||||
module.add(allocateArray("teavm_allocateCharArray", ValueType.parse(char.class)));
|
||||
module.add(allocateArray("teavm_allocateIntArray", ValueType.parse(int.class)));
|
||||
module.add(allocateArray("teavm_allocateLongArray", ValueType.parse(long.class)));
|
||||
module.add(allocateArray("teavm_allocateFloatArray", ValueType.parse(float.class)));
|
||||
module.add(allocateArray("teavm_allocateDoubleArray", ValueType.parse(double.class)));
|
||||
module.add(arrayData("teavm_objectArrayData", 4));
|
||||
module.add(arrayData("teavm_byteArrayData", 1));
|
||||
module.add(arrayData("teavm_shortArrayData", 2));
|
||||
module.add(arrayData("teavm_charArrayData", 2));
|
||||
module.add(arrayData("teavm_intArrayData", 4));
|
||||
module.add(arrayData("teavm_longArrayData", 8));
|
||||
module.add(arrayData("teavm_floatArrayData", 4));
|
||||
module.add(arrayData("teavm_doubleArrayData", 8));
|
||||
module.add(arrayLength());
|
||||
module.functions.add(allocateArray("teavm_allocateObjectArray", ValueType.parse(Object.class)));
|
||||
module.functions.add(allocateArray("teavm_allocateStringArray", ValueType.parse(String.class)));
|
||||
module.functions.add(allocateArray("teavm_allocateByteArray", ValueType.parse(byte.class)));
|
||||
module.functions.add(allocateArray("teavm_allocateShortArray", ValueType.parse(short.class)));
|
||||
module.functions.add(allocateArray("teavm_allocateCharArray", ValueType.parse(char.class)));
|
||||
module.functions.add(allocateArray("teavm_allocateIntArray", ValueType.parse(int.class)));
|
||||
module.functions.add(allocateArray("teavm_allocateLongArray", ValueType.parse(long.class)));
|
||||
module.functions.add(allocateArray("teavm_allocateFloatArray", ValueType.parse(float.class)));
|
||||
module.functions.add(allocateArray("teavm_allocateDoubleArray", ValueType.parse(double.class)));
|
||||
module.functions.add(arrayData("teavm_objectArrayData", 4));
|
||||
module.functions.add(arrayData("teavm_byteArrayData", 1));
|
||||
module.functions.add(arrayData("teavm_shortArrayData", 2));
|
||||
module.functions.add(arrayData("teavm_charArrayData", 2));
|
||||
module.functions.add(arrayData("teavm_intArrayData", 4));
|
||||
module.functions.add(arrayData("teavm_longArrayData", 8));
|
||||
module.functions.add(arrayData("teavm_floatArrayData", 4));
|
||||
module.functions.add(arrayData("teavm_doubleArrayData", 8));
|
||||
module.functions.add(arrayLength());
|
||||
}
|
||||
|
||||
|
||||
private WasmFunction allocateString() {
|
||||
WasmFunction function = new WasmFunction("teavm_allocateString");
|
||||
var function = new WasmFunction(functionTypes.of(WasmType.INT32, WasmType.INT32));
|
||||
function.setName("teavm_allocateString");
|
||||
function.setExportName(function.getName());
|
||||
function.setResult(WasmType.INT32);
|
||||
function.getParameters().add(WasmType.INT32);
|
||||
|
||||
WasmLocal sizeLocal = new WasmLocal(WasmType.INT32, "size");
|
||||
function.add(sizeLocal);
|
||||
|
||||
String constructorName = classGenerator.names.forMethod(new MethodReference(String.class, "allocate",
|
||||
var constructor = classGenerator.functions.forStaticMethod(new MethodReference(String.class, "allocate",
|
||||
int.class, String.class));
|
||||
WasmCall constructorCall = new WasmCall(constructorName);
|
||||
WasmCall constructorCall = new WasmCall(constructor);
|
||||
constructorCall.getArguments().add(new WasmGetLocal(sizeLocal));
|
||||
function.getBody().add(constructorCall);
|
||||
|
||||
|
@ -90,18 +92,17 @@ public class WasmInteropFunctionGenerator {
|
|||
}
|
||||
|
||||
private WasmFunction allocateArray(String name, ValueType type) {
|
||||
WasmFunction function = new WasmFunction(name);
|
||||
var function = new WasmFunction(functionTypes.of(WasmType.INT32, WasmType.INT32));
|
||||
function.setName(name);
|
||||
function.setExportName(name);
|
||||
function.setResult(WasmType.INT32);
|
||||
function.getParameters().add(WasmType.INT32);
|
||||
|
||||
WasmLocal sizeLocal = new WasmLocal(WasmType.INT32, "size");
|
||||
function.add(sizeLocal);
|
||||
|
||||
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type));
|
||||
String allocName = classGenerator.names.forMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||
RuntimeClass.class, int.class, Address.class));
|
||||
WasmCall call = new WasmCall(allocName);
|
||||
var allocFunction = classGenerator.functions.forStaticMethod(new MethodReference(Allocator.class,
|
||||
"allocateArray", RuntimeClass.class, int.class, Address.class));
|
||||
WasmCall call = new WasmCall(allocFunction);
|
||||
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||
call.getArguments().add(new WasmGetLocal(sizeLocal));
|
||||
|
||||
|
@ -111,10 +112,9 @@ public class WasmInteropFunctionGenerator {
|
|||
}
|
||||
|
||||
private WasmFunction stringData() {
|
||||
WasmFunction function = new WasmFunction("teavm_stringData");
|
||||
var function = new WasmFunction(functionTypes.of(WasmType.INT32, WasmType.INT32));
|
||||
function.setName("teavm_stringData");
|
||||
function.setExportName(function.getName());
|
||||
function.setResult(WasmType.INT32);
|
||||
function.getParameters().add(WasmType.INT32);
|
||||
|
||||
WasmLocal stringLocal = new WasmLocal(WasmType.INT32, "string");
|
||||
function.add(stringLocal);
|
||||
|
@ -128,10 +128,9 @@ public class WasmInteropFunctionGenerator {
|
|||
}
|
||||
|
||||
private WasmFunction arrayData(String name, int alignment) {
|
||||
WasmFunction function = new WasmFunction(name);
|
||||
var function = new WasmFunction(functionTypes.of(WasmType.INT32, WasmType.INT32));
|
||||
function.setName(name);
|
||||
function.setExportName(function.getName());
|
||||
function.setResult(WasmType.INT32);
|
||||
function.getParameters().add(WasmType.INT32);
|
||||
|
||||
WasmLocal arrayLocal = new WasmLocal(WasmType.INT32, "array");
|
||||
function.add(arrayLocal);
|
||||
|
@ -147,10 +146,9 @@ public class WasmInteropFunctionGenerator {
|
|||
}
|
||||
|
||||
private WasmFunction arrayLength() {
|
||||
WasmFunction function = new WasmFunction("teavm_arrayLength");
|
||||
WasmFunction function = new WasmFunction(functionTypes.of(WasmType.INT32, WasmType.INT32));
|
||||
function.setName("teavm_arrayLength");
|
||||
function.setExportName(function.getName());
|
||||
function.setResult(WasmType.INT32);
|
||||
function.getParameters().add(WasmType.INT32);
|
||||
|
||||
WasmLocal arrayLocal = new WasmLocal(WasmType.INT32, "array");
|
||||
function.add(arrayLocal);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.backend.wasm.generate;
|
||||
|
||||
import java.util.List;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.WasmHeap;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
|
@ -28,25 +29,27 @@ import org.teavm.model.FieldReference;
|
|||
|
||||
public class WasmSpecialFunctionGenerator {
|
||||
private WasmClassGenerator classGenerator;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private List<WasmInt32Constant> regionSizeExpressions;
|
||||
|
||||
public WasmSpecialFunctionGenerator(WasmClassGenerator classGenerator,
|
||||
public WasmSpecialFunctionGenerator(WasmClassGenerator classGenerator, WasmFunctionTypes functionTypes,
|
||||
List<WasmInt32Constant> regionSizeExpressions) {
|
||||
this.classGenerator = classGenerator;
|
||||
this.functionTypes = functionTypes;
|
||||
this.regionSizeExpressions = regionSizeExpressions;
|
||||
}
|
||||
|
||||
public void generateSpecialFunctions(WasmModule module) {
|
||||
module.add(javaHeapAddress());
|
||||
module.add(availableBytes());
|
||||
module.add(regionsAddress());
|
||||
module.add(regionSize());
|
||||
module.functions.add(javaHeapAddress());
|
||||
module.functions.add(availableBytes());
|
||||
module.functions.add(regionsAddress());
|
||||
module.functions.add(regionSize());
|
||||
}
|
||||
|
||||
private WasmFunction javaHeapAddress() {
|
||||
WasmFunction function = new WasmFunction("teavm_javaHeapAddress");
|
||||
var function = new WasmFunction(functionTypes.of(WasmType.INT32));
|
||||
function.setName("teavm_javaHeapAddress");
|
||||
function.setExportName("teavm_javaHeapAddress");
|
||||
function.setResult(WasmType.INT32);
|
||||
|
||||
int address = classGenerator.getFieldOffset(new FieldReference(WasmHeap.class.getName(), "heapAddress"));
|
||||
function.getBody().add(new WasmReturn(
|
||||
|
@ -55,9 +58,9 @@ public class WasmSpecialFunctionGenerator {
|
|||
}
|
||||
|
||||
private WasmFunction availableBytes() {
|
||||
WasmFunction function = new WasmFunction("teavm_availableBytes");
|
||||
var function = new WasmFunction(functionTypes.of(WasmType.INT32));
|
||||
function.setName("teavm_availableBytes");
|
||||
function.setExportName("teavm_availableBytes");
|
||||
function.setResult(WasmType.INT32);
|
||||
|
||||
int address = classGenerator.getFieldOffset(new FieldReference(WasmHeap.class.getName(), "heapSize"));
|
||||
function.getBody().add(new WasmReturn(
|
||||
|
@ -66,9 +69,9 @@ public class WasmSpecialFunctionGenerator {
|
|||
}
|
||||
|
||||
private WasmFunction regionsAddress() {
|
||||
WasmFunction function = new WasmFunction("teavm_regionsAddress");
|
||||
var function = new WasmFunction(functionTypes.of(WasmType.INT32));
|
||||
function.setExportName("teavm_regionsAddress");
|
||||
function.setResult(WasmType.INT32);
|
||||
function.setName("teavm_regionsAddress");
|
||||
|
||||
int address = classGenerator.getFieldOffset(new FieldReference(WasmHeap.class.getName(), "regionsAddress"));
|
||||
function.getBody().add(new WasmReturn(
|
||||
|
@ -77,9 +80,9 @@ public class WasmSpecialFunctionGenerator {
|
|||
}
|
||||
|
||||
private WasmFunction regionSize() {
|
||||
WasmFunction function = new WasmFunction("teavm_regionSize");
|
||||
var function = new WasmFunction(functionTypes.of(WasmType.INT32));
|
||||
function.setExportName("teavm_regionSize");
|
||||
function.setResult(WasmType.INT32);
|
||||
function.setName("teavm_regionSize");
|
||||
|
||||
WasmInt32Constant constant = new WasmInt32Constant(0);
|
||||
regionSizeExpressions.add(constant);
|
||||
|
|
|
@ -133,7 +133,7 @@ public class ArrayGenerator implements WasmMethodGenerator {
|
|||
new WasmGetLocal(arrayVar));
|
||||
int baseAddr = BinaryWriter.align(base, 1 << shift[i]);
|
||||
|
||||
WasmCall call = new WasmCall(context.getNames().forMethod(methodRef));
|
||||
WasmCall call = new WasmCall(context.getFunctions().forStaticMethod(methodRef));
|
||||
|
||||
switch (primitiveTypes[i].getKind()) {
|
||||
case BOOLEAN:
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.generators;
|
||||
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||
|
@ -29,7 +29,7 @@ public interface WasmMethodGeneratorContext {
|
|||
|
||||
Diagnostics getDiagnostics();
|
||||
|
||||
NameProvider getNames();
|
||||
WasmFunctionRepository getFunctions();
|
||||
|
||||
ClassReaderSource getClassSource();
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.teavm.ast.ConstantExpr;
|
|||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||
import org.teavm.backend.wasm.model.expression.WasmDrop;
|
||||
|
@ -64,21 +64,21 @@ public class AddressIntrinsic implements WasmIntrinsic {
|
|||
return manager.generate(invocation.getArguments().get(0));
|
||||
case "toLong": {
|
||||
WasmExpression value = manager.generate(invocation.getArguments().get(0));
|
||||
return new WasmConversion(WasmType.INT32, WasmType.INT64, false, value);
|
||||
return new WasmConversion(WasmNumType.INT32, WasmNumType.INT64, false, value);
|
||||
}
|
||||
case "fromInt":
|
||||
case "ofObject":
|
||||
return manager.generate(invocation.getArguments().get(0));
|
||||
case "fromLong": {
|
||||
WasmExpression value = manager.generate(invocation.getArguments().get(0));
|
||||
return new WasmConversion(WasmType.INT64, WasmType.INT32, false, value);
|
||||
return new WasmConversion(WasmNumType.INT64, WasmNumType.INT32, false, value);
|
||||
}
|
||||
case "add": {
|
||||
WasmExpression base = manager.generate(invocation.getArguments().get(0));
|
||||
if (invocation.getMethod().parameterCount() == 1) {
|
||||
WasmExpression offset = manager.generate(invocation.getArguments().get(1));
|
||||
if (invocation.getMethod().parameterType(0) == ValueType.LONG) {
|
||||
offset = new WasmConversion(WasmType.INT64, WasmType.INT32, false, offset);
|
||||
offset = new WasmConversion(WasmNumType.INT64, WasmNumType.INT32, false, offset);
|
||||
}
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
|
||||
} else {
|
||||
|
@ -155,7 +155,7 @@ public class AddressIntrinsic implements WasmIntrinsic {
|
|||
case "align": {
|
||||
MethodReference delegate = new MethodReference(WasmRuntime.class.getName(),
|
||||
invocation.getMethod().getDescriptor());
|
||||
WasmCall call = new WasmCall(manager.getNames().forMethod(delegate));
|
||||
WasmCall call = new WasmCall(manager.getFunctions().forStaticMethod(delegate));
|
||||
call.getArguments().addAll(invocation.getArguments().stream()
|
||||
.map(arg -> manager.generate(arg))
|
||||
.collect(Collectors.toList()));
|
||||
|
@ -180,7 +180,7 @@ public class AddressIntrinsic implements WasmIntrinsic {
|
|||
manager.generate(invocation.getArguments().get(0)),
|
||||
manager.generate(invocation.getArguments().get(1))
|
||||
);
|
||||
result = new WasmConversion(WasmType.INT32, WasmType.INT64, true, result);
|
||||
result = new WasmConversion(WasmNumType.INT32, WasmNumType.INT64, true, result);
|
||||
result.setLocation(invocation.getLocation());
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -48,14 +48,14 @@ public class ConsoleIntrinsic implements WasmIntrinsic {
|
|||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "printString": {
|
||||
String name = manager.getNames().forMethod(PRINT_STRING);
|
||||
WasmCall call = new WasmCall(name);
|
||||
var function = manager.getFunctions().forStaticMethod(PRINT_STRING);
|
||||
var call = new WasmCall(function);
|
||||
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
|
||||
return call;
|
||||
}
|
||||
case "printInt": {
|
||||
String name = manager.getNames().forMethod(PRINT_INT);
|
||||
WasmCall call = new WasmCall(name);
|
||||
var function = manager.getFunctions().forStaticMethod(PRINT_INT);
|
||||
var call = new WasmCall(function);
|
||||
call.getArguments().add(manager.generate(invocation.getArguments().get(0)));
|
||||
return call;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.backend.wasm.intrinsics;
|
|||
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -68,13 +69,13 @@ public class DoubleIntrinsic implements WasmIntrinsic {
|
|||
case "isFinite":
|
||||
return testIsFinite(manager.generate(invocation.getArguments().get(0)));
|
||||
case "doubleToRawLongBits": {
|
||||
WasmConversion conversion = new WasmConversion(WasmType.FLOAT64, WasmType.INT64, false,
|
||||
WasmConversion conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false,
|
||||
manager.generate(invocation.getArguments().get(0)));
|
||||
conversion.setReinterpret(true);
|
||||
return conversion;
|
||||
}
|
||||
case "longBitsToDouble": {
|
||||
WasmConversion conversion = new WasmConversion(WasmType.INT64, WasmType.FLOAT64, false,
|
||||
WasmConversion conversion = new WasmConversion(WasmNumType.INT64, WasmNumType.FLOAT64, false,
|
||||
manager.generate(invocation.getArguments().get(0)));
|
||||
conversion.setReinterpret(true);
|
||||
return conversion;
|
||||
|
@ -89,7 +90,7 @@ public class DoubleIntrinsic implements WasmIntrinsic {
|
|||
WasmBlock block = new WasmBlock(false);
|
||||
block.setType(WasmType.INT32);
|
||||
|
||||
WasmConversion conversion = new WasmConversion(WasmType.FLOAT64, WasmType.INT64, false, expression);
|
||||
WasmConversion conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
|
||||
conversion.setReinterpret(true);
|
||||
block.getBody().add(new WasmSetLocal(bitsVar, conversion));
|
||||
|
||||
|
@ -113,7 +114,7 @@ public class DoubleIntrinsic implements WasmIntrinsic {
|
|||
}
|
||||
|
||||
private WasmExpression testIsInfinite(WasmExpression expression) {
|
||||
var conversion = new WasmConversion(WasmType.FLOAT64, WasmType.INT64, false, expression);
|
||||
var conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
|
||||
conversion.setReinterpret(true);
|
||||
|
||||
var result = new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.AND,
|
||||
|
@ -123,7 +124,7 @@ public class DoubleIntrinsic implements WasmIntrinsic {
|
|||
}
|
||||
|
||||
private WasmExpression testIsFinite(WasmExpression expression) {
|
||||
var conversion = new WasmConversion(WasmType.FLOAT64, WasmType.INT64, false, expression);
|
||||
var conversion = new WasmConversion(WasmNumType.FLOAT64, WasmNumType.INT64, false, expression);
|
||||
conversion.setReinterpret(true);
|
||||
|
||||
var result = new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.AND,
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.backend.wasm.intrinsics;
|
|||
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -67,13 +68,13 @@ public class FloatIntrinsic implements WasmIntrinsic {
|
|||
case "isFinite":
|
||||
return testIsFinite(manager.generate(invocation.getArguments().get(0)));
|
||||
case "floatToRawIntBits": {
|
||||
WasmConversion conversion = new WasmConversion(WasmType.FLOAT32, WasmType.INT32, false,
|
||||
WasmConversion conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false,
|
||||
manager.generate(invocation.getArguments().get(0)));
|
||||
conversion.setReinterpret(true);
|
||||
return conversion;
|
||||
}
|
||||
case "intBitsToFloat": {
|
||||
WasmConversion conversion = new WasmConversion(WasmType.INT32, WasmType.FLOAT32, false,
|
||||
WasmConversion conversion = new WasmConversion(WasmNumType.INT32, WasmNumType.FLOAT32, false,
|
||||
manager.generate(invocation.getArguments().get(0)));
|
||||
conversion.setReinterpret(true);
|
||||
return conversion;
|
||||
|
@ -88,7 +89,7 @@ public class FloatIntrinsic implements WasmIntrinsic {
|
|||
WasmBlock block = new WasmBlock(false);
|
||||
block.setType(WasmType.INT32);
|
||||
|
||||
WasmConversion conversion = new WasmConversion(WasmType.FLOAT32, WasmType.INT32, false, expression);
|
||||
WasmConversion conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
|
||||
conversion.setReinterpret(true);
|
||||
block.getBody().add(new WasmSetLocal(bitsVar, conversion));
|
||||
|
||||
|
@ -112,7 +113,7 @@ public class FloatIntrinsic implements WasmIntrinsic {
|
|||
}
|
||||
|
||||
private WasmExpression testIsInfinite(WasmExpression expression) {
|
||||
var conversion = new WasmConversion(WasmType.FLOAT32, WasmType.INT32, false, expression);
|
||||
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
|
||||
conversion.setReinterpret(true);
|
||||
|
||||
var result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND,
|
||||
|
@ -122,7 +123,7 @@ public class FloatIntrinsic implements WasmIntrinsic {
|
|||
}
|
||||
|
||||
private WasmExpression testIsFinite(WasmExpression expression) {
|
||||
var conversion = new WasmConversion(WasmType.FLOAT32, WasmType.INT32, false, expression);
|
||||
var conversion = new WasmConversion(WasmNumType.FLOAT32, WasmNumType.INT32, false, expression);
|
||||
conversion.setReinterpret(true);
|
||||
|
||||
var result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND,
|
||||
|
|
|
@ -18,11 +18,11 @@ package org.teavm.backend.wasm.intrinsics;
|
|||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.backend.wasm.generate.WasmGeneratorUtil;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
import org.teavm.interop.Function;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class FunctionIntrinsic implements WasmIntrinsic {
|
||||
private WasmClassGenerator classGenerator;
|
||||
|
@ -42,15 +42,16 @@ public class FunctionIntrinsic implements WasmIntrinsic {
|
|||
|
||||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
WasmExpression selector = manager.generate(invocation.getArguments().get(0));
|
||||
WasmIndirectCall call = new WasmIndirectCall(selector);
|
||||
var parameterTypes = new WasmType[invocation.getMethod().parameterCount()];
|
||||
for (var i = 0; i < parameterTypes.length; ++i) {
|
||||
parameterTypes[i] = WasmGeneratorUtil.mapType(invocation.getMethod().parameterType(i));
|
||||
}
|
||||
var returnType = WasmGeneratorUtil.mapType(invocation.getMethod().getReturnType());
|
||||
var functionType = manager.getFunctionTypes().of(returnType, parameterTypes);
|
||||
|
||||
var selector = manager.generate(invocation.getArguments().get(0));
|
||||
var call = new WasmIndirectCall(selector, functionType);
|
||||
|
||||
for (ValueType type : invocation.getMethod().getParameterTypes()) {
|
||||
call.getParameterTypes().add(WasmGeneratorUtil.mapType(type));
|
||||
}
|
||||
if (invocation.getMethod().getReturnType() != ValueType.VOID) {
|
||||
call.setReturnType(WasmGeneratorUtil.mapType(invocation.getMethod().getReturnType()));
|
||||
}
|
||||
for (int i = 1; i < invocation.getArguments().size(); ++i) {
|
||||
call.getArguments().add(manager.generate(invocation.getArguments().get(i)));
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.List;
|
|||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.WasmHeap;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||
|
@ -100,8 +100,8 @@ public class GCIntrinsic implements WasmIntrinsic {
|
|||
return intToLong(getStaticField(manager, "maxHeapSize"));
|
||||
case "resizeHeap": {
|
||||
WasmExpression amount = manager.generate(invocation.getArguments().get(0));
|
||||
amount = new WasmConversion(WasmType.INT64, WasmType.INT32, false, amount);
|
||||
return new WasmCall(manager.getNames().forMethod(RESIZE_HEAP), amount);
|
||||
amount = new WasmConversion(WasmNumType.INT64, WasmNumType.INT32, false, amount);
|
||||
return new WasmCall(manager.getFunctions().forStaticMethod(RESIZE_HEAP), amount);
|
||||
}
|
||||
case "regionSize": {
|
||||
WasmInt32Constant result = new WasmInt32Constant(0);
|
||||
|
@ -112,7 +112,7 @@ public class GCIntrinsic implements WasmIntrinsic {
|
|||
return intToLong(getStaticField(manager, "heapSize"));
|
||||
case "outOfMemory": {
|
||||
WasmBlock block = new WasmBlock(false);
|
||||
WasmCall call = new WasmCall(manager.getNames().forMethod(PRINT_OUT_OF_MEMORY));
|
||||
WasmCall call = new WasmCall(manager.getFunctions().forStaticMethod(PRINT_OUT_OF_MEMORY));
|
||||
block.getBody().add(call);
|
||||
block.getBody().add(new WasmUnreachable());
|
||||
return block;
|
||||
|
@ -149,6 +149,6 @@ public class GCIntrinsic implements WasmIntrinsic {
|
|||
}
|
||||
|
||||
private static WasmExpression intToLong(WasmExpression expression) {
|
||||
return new WasmConversion(WasmType.INT32, WasmType.INT64, false, expression);
|
||||
return new WasmConversion(WasmNumType.INT32, WasmNumType.INT64, false, expression);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public class IntegerIntrinsic implements WasmIntrinsic {
|
|||
manager.generate(invocation.getArguments().get(0)),
|
||||
manager.generate(invocation.getArguments().get(1)));
|
||||
case "compareUnsigned":
|
||||
return new WasmCall(manager.getNames().forMethod(COMPARE_UNSIGNED),
|
||||
return new WasmCall(manager.getFunctions().forStaticMethod(COMPARE_UNSIGNED),
|
||||
manager.generate(invocation.getArguments().get(0)),
|
||||
manager.generate(invocation.getArguments().get(1)));
|
||||
default:
|
||||
|
|
|
@ -56,7 +56,7 @@ public class LongIntrinsic implements WasmIntrinsic {
|
|||
manager.generate(invocation.getArguments().get(0)),
|
||||
manager.generate(invocation.getArguments().get(1)));
|
||||
case "compareUnsigned":
|
||||
return new WasmCall(manager.getNames().forMethod(COMPARE_UNSIGNED),
|
||||
return new WasmCall(manager.getFunctions().forStaticMethod(COMPARE_UNSIGNED),
|
||||
manager.generate(invocation.getArguments().get(0)),
|
||||
manager.generate(invocation.getArguments().get(1)));
|
||||
default:
|
||||
|
|
|
@ -49,7 +49,7 @@ public class ShadowStackIntrinsic implements WasmIntrinsic {
|
|||
MethodReference method = new MethodReference(WasmRuntime.class.getName(),
|
||||
invocation.getMethod().getDescriptor());
|
||||
expr.setMethod(method);
|
||||
expr.setType(InvocationType.SPECIAL);
|
||||
expr.setType(InvocationType.STATIC);
|
||||
expr.getArguments().addAll(invocation.getArguments());
|
||||
return manager.generate(expr);
|
||||
}
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
package org.teavm.backend.wasm.intrinsics;
|
||||
|
||||
import org.teavm.ast.Expr;
|
||||
import org.teavm.backend.lowlevel.generate.NameProvider;
|
||||
import org.teavm.backend.wasm.WasmFunctionRepository;
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmTag;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
@ -38,7 +40,9 @@ public interface WasmIntrinsicManager {
|
|||
|
||||
Diagnostics getDiagnostics();
|
||||
|
||||
NameProvider getNames();
|
||||
WasmFunctionRepository getFunctions();
|
||||
|
||||
WasmFunctionTypes getFunctionTypes();
|
||||
|
||||
WasmLocal getTemporary(WasmType type);
|
||||
|
||||
|
@ -46,7 +50,7 @@ public interface WasmIntrinsicManager {
|
|||
|
||||
int getClassPointer(ValueType type);
|
||||
|
||||
int getFunctionPointer(String name);
|
||||
int getFunctionPointer(WasmFunction function);
|
||||
|
||||
void releaseTemporary(WasmLocal local);
|
||||
|
||||
|
|
|
@ -72,8 +72,8 @@ public class WasmRuntimeIntrinsic implements WasmIntrinsic {
|
|||
return comparison(WasmIntBinaryOperation.GT_SIGNED, WasmFloatBinaryOperation.MAX,
|
||||
invocation, manager);
|
||||
case "callFunctionFromTable": {
|
||||
var call = new WasmIndirectCall(manager.generate(invocation.getArguments().get(0)));
|
||||
call.getParameterTypes().add(WasmType.INT32);
|
||||
var functionType = manager.getFunctionTypes().of(null, WasmType.INT32);
|
||||
var call = new WasmIndirectCall(manager.generate(invocation.getArguments().get(0)), functionType);
|
||||
call.getArguments().add(manager.generate(invocation.getArguments().get(1)));
|
||||
return call;
|
||||
}
|
||||
|
@ -84,12 +84,12 @@ public class WasmRuntimeIntrinsic implements WasmIntrinsic {
|
|||
|
||||
private static WasmExpression comparison(WasmIntBinaryOperation intOp, WasmFloatBinaryOperation floatOp,
|
||||
InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
WasmType type = WasmGeneratorUtil.mapType(invocation.getMethod().parameterType(0));
|
||||
var type = (WasmType.Number) WasmGeneratorUtil.mapType(invocation.getMethod().parameterType(0));
|
||||
|
||||
WasmExpression first = manager.generate(invocation.getArguments().get(0));
|
||||
WasmExpression second = manager.generate(invocation.getArguments().get(1));
|
||||
|
||||
switch (type) {
|
||||
switch (type.number) {
|
||||
case INT32:
|
||||
return new WasmIntBinary(WasmIntType.INT32, intOp, first, second);
|
||||
case INT64:
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WasmArray extends WasmCompositeType {
|
||||
private WasmStorageType elementType;
|
||||
private Supplier<WasmStorageType> elementTypeSupplier;
|
||||
|
||||
public WasmArray(WasmStorageType elementType) {
|
||||
this.elementType = Objects.requireNonNull(elementType);
|
||||
}
|
||||
|
||||
public WasmArray(Supplier<WasmStorageType> elementTypeSupplier) {
|
||||
this.elementTypeSupplier = elementTypeSupplier;
|
||||
}
|
||||
|
||||
public WasmStorageType getElementType() {
|
||||
if (elementType == null) {
|
||||
elementType = elementTypeSupplier.get();
|
||||
elementTypeSupplier = null;
|
||||
}
|
||||
return elementType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class WasmCollection<T extends WasmEntity> implements Iterable<T> {
|
||||
private List<T> items = new ArrayList<>();
|
||||
private List<T> readonlyItems = Collections.unmodifiableList(items);
|
||||
private boolean indexesInvalid;
|
||||
|
||||
WasmCollection() {
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return items.isEmpty();
|
||||
}
|
||||
|
||||
public void add(T entity) {
|
||||
if (!indexesInvalid) {
|
||||
entity.index = items.size();
|
||||
}
|
||||
entity.collection = this;
|
||||
items.add(entity);
|
||||
}
|
||||
|
||||
public void removeIf(Predicate<T> predicate) {
|
||||
for (var item : items) {
|
||||
if (predicate.test(item)) {
|
||||
item.collection = null;
|
||||
}
|
||||
}
|
||||
if (items.removeIf(predicate)) {
|
||||
invalidateIndexes();
|
||||
}
|
||||
}
|
||||
|
||||
void invalidateIndexes() {
|
||||
indexesInvalid = true;
|
||||
}
|
||||
|
||||
public int indexOf(T entity) {
|
||||
if (entity.collection != this) {
|
||||
throw new IllegalArgumentException("Given entity does not belong to this module");
|
||||
}
|
||||
if (indexesInvalid) {
|
||||
indexesInvalid = false;
|
||||
var index = 0;
|
||||
for (var item : items) {
|
||||
if (item.isImported()) {
|
||||
item.index = index++;
|
||||
}
|
||||
}
|
||||
for (var item : items) {
|
||||
if (!item.isImported()) {
|
||||
item.index = index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return entity.index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return readonlyItems.iterator();
|
||||
}
|
||||
|
||||
public Stream<T> stream() {
|
||||
return readonlyItems.stream();
|
||||
}
|
||||
}
|
|
@ -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.model;
|
||||
|
||||
public abstract class WasmCompositeType extends WasmEntity {
|
||||
private WasmType.Reference reference;
|
||||
|
||||
WasmCompositeType() {
|
||||
}
|
||||
|
||||
public WasmType.Reference getReference() {
|
||||
if (reference == null) {
|
||||
reference = new WasmType.Reference(this);
|
||||
}
|
||||
return reference;
|
||||
}
|
||||
|
||||
public abstract void acceptVisitor(WasmCompositeTypeVisitor visitor);
|
||||
}
|
|
@ -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.backend.wasm.model;
|
||||
|
||||
public interface WasmCompositeTypeVisitor {
|
||||
void visit(WasmStructure type);
|
||||
|
||||
void visit(WasmArray type);
|
||||
|
||||
void visit(WasmFunctionType type);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public class WasmDefaultCompositeTypeVisitor implements WasmCompositeTypeVisitor {
|
||||
@Override
|
||||
public void visit(WasmStructure type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArray type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionType type) {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public abstract class WasmEntity {
|
||||
int index;
|
||||
WasmCollection<?> collection;
|
||||
|
||||
boolean isImported() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -22,32 +22,29 @@ import java.util.Objects;
|
|||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WasmFunction {
|
||||
WasmModule module;
|
||||
public class WasmFunction extends WasmEntity {
|
||||
private String name;
|
||||
private String exportName;
|
||||
private String importName;
|
||||
private String importModule;
|
||||
private List<WasmType> parameters = new ArrayList<>();
|
||||
private WasmType result;
|
||||
private WasmFunctionType type;
|
||||
private List<WasmLocal> localVariables = new ArrayList<>();
|
||||
private List<WasmLocal> readonlyLocalVariables = Collections.unmodifiableList(localVariables);
|
||||
private List<WasmExpression> body = new ArrayList<>();
|
||||
private MethodReference javaMethod;
|
||||
|
||||
public WasmFunction(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public WasmModule getModule() {
|
||||
return module;
|
||||
public WasmFunction(WasmFunctionType type) {
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getExportName() {
|
||||
return exportName;
|
||||
}
|
||||
|
@ -62,6 +59,7 @@ public class WasmFunction {
|
|||
|
||||
public void setImportName(String importName) {
|
||||
this.importName = importName;
|
||||
collection.invalidateIndexes();
|
||||
}
|
||||
|
||||
public String getImportModule() {
|
||||
|
@ -72,16 +70,17 @@ public class WasmFunction {
|
|||
this.importModule = importModule;
|
||||
}
|
||||
|
||||
public WasmType getResult() {
|
||||
return result;
|
||||
@Override
|
||||
boolean isImported() {
|
||||
return importName != null;
|
||||
}
|
||||
|
||||
public void setResult(WasmType result) {
|
||||
this.result = result;
|
||||
public WasmFunctionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public List<WasmType> getParameters() {
|
||||
return parameters;
|
||||
public void setType(WasmFunctionType type) {
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
public List<WasmLocal> getLocalVariables() {
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WasmFunctionType extends WasmCompositeType {
|
||||
private List<? extends WasmType> parameterTypes;
|
||||
private WasmType returnType;
|
||||
private Supplier<List<? extends WasmType>> parameterTypesSupplier;
|
||||
private Supplier<WasmType> returnTypeSupplier;
|
||||
|
||||
public WasmFunctionType(WasmType returnType, List<? extends WasmType> parameterTypes) {
|
||||
this.returnType = returnType;
|
||||
this.parameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
public WasmFunctionType(Supplier<WasmType> returnTypeSupplier,
|
||||
Supplier<List<? extends WasmType>> parameterTypesSupplier) {
|
||||
this.returnTypeSupplier = returnTypeSupplier;
|
||||
this.parameterTypesSupplier = parameterTypesSupplier;
|
||||
}
|
||||
|
||||
public List<? extends WasmType> getParameterTypes() {
|
||||
if (parameterTypes == null) {
|
||||
parameterTypes = List.copyOf(parameterTypesSupplier.get());
|
||||
parameterTypesSupplier = null;
|
||||
}
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
public WasmType getReturnType() {
|
||||
if (returnTypeSupplier != null) {
|
||||
returnType = returnTypeSupplier.get();
|
||||
returnTypeSupplier = null;
|
||||
}
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -25,37 +25,14 @@ public class WasmModule {
|
|||
private int minMemorySize;
|
||||
private int maxMemorySize;
|
||||
private List<WasmMemorySegment> segments = new ArrayList<>();
|
||||
private Map<String, WasmFunction> functions = new LinkedHashMap<>();
|
||||
private Map<String, WasmFunction> readonlyFunctions = Collections.unmodifiableMap(functions);
|
||||
private List<WasmFunction> functionTable = new ArrayList<>();
|
||||
private WasmFunction startFunction;
|
||||
private Map<String, WasmCustomSection> customSections = new LinkedHashMap<>();
|
||||
private Map<String, WasmCustomSection> readonlyCustomSections = Collections.unmodifiableMap(customSections);
|
||||
private List<WasmTag> tags = new ArrayList<>();
|
||||
private List<? extends WasmTag> readonlyTags = Collections.unmodifiableList(tags);
|
||||
|
||||
public void add(WasmFunction function) {
|
||||
if (functions.containsKey(function.getName())) {
|
||||
throw new IllegalArgumentException("Function " + function.getName() + " already defined in this module");
|
||||
}
|
||||
if (function.module != null) {
|
||||
throw new IllegalArgumentException("Given function is already registered in another module");
|
||||
}
|
||||
functions.put(function.getName(), function);
|
||||
function.module = this;
|
||||
}
|
||||
|
||||
public void remove(WasmFunction function) {
|
||||
if (function.getModule() != this) {
|
||||
return;
|
||||
}
|
||||
function.module = null;
|
||||
functions.remove(function.getName());
|
||||
}
|
||||
|
||||
public Map<String, WasmFunction> getFunctions() {
|
||||
return readonlyFunctions;
|
||||
}
|
||||
public final WasmCollection<WasmFunction> functions = new WasmCollection<>();
|
||||
public final WasmCollection<WasmCompositeType> types = new WasmCollection<>();
|
||||
public final WasmCollection<WasmTag> tags = new WasmCollection<>();
|
||||
|
||||
public void add(WasmCustomSection customSection) {
|
||||
if (customSections.containsKey(customSection.getName())) {
|
||||
|
@ -112,17 +89,4 @@ public class WasmModule {
|
|||
public void setStartFunction(WasmFunction startFunction) {
|
||||
this.startFunction = startFunction;
|
||||
}
|
||||
|
||||
public void addTag(WasmTag tag) {
|
||||
if (tag.module != null) {
|
||||
throw new IllegalArgumentException("Given tag already belongs to some module");
|
||||
}
|
||||
tags.add(tag);
|
||||
tag.module = this;
|
||||
tag.index = tags.size() - 1;
|
||||
}
|
||||
|
||||
public List<? extends WasmTag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.model;
|
||||
|
||||
public enum WasmNumType {
|
||||
INT32,
|
||||
INT64,
|
||||
FLOAT32,
|
||||
FLOAT64
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public enum WasmPackedType {
|
||||
INT8,
|
||||
INT16
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public abstract class WasmStorageType {
|
||||
private static final Packed INT16 = new Packed(WasmPackedType.INT16);
|
||||
private static final Packed INT8 = new Packed(WasmPackedType.INT8);
|
||||
|
||||
private WasmStorageType() {
|
||||
}
|
||||
|
||||
public static WasmStorageType.Packed packed(WasmPackedType type) {
|
||||
switch (type) {
|
||||
case INT8:
|
||||
return INT8;
|
||||
case INT16:
|
||||
return INT16;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Regular extends WasmStorageType {
|
||||
public final WasmType type;
|
||||
|
||||
Regular(WasmType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Packed extends WasmStorageType {
|
||||
public final WasmPackedType type;
|
||||
|
||||
private Packed(WasmPackedType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WasmStructure extends WasmCompositeType {
|
||||
private List<? extends WasmStorageType> fields;
|
||||
private Supplier<List<? extends WasmStorageType>> fieldsSupplier;
|
||||
|
||||
public WasmStructure(List<? extends WasmStorageType> fields) {
|
||||
this.fields = List.copyOf(fields);
|
||||
}
|
||||
|
||||
public WasmStructure(Supplier<List<? extends WasmStorageType>> fieldsSupplier) {
|
||||
this.fieldsSupplier = fieldsSupplier;
|
||||
}
|
||||
|
||||
public List<? extends WasmStorageType> getFields() {
|
||||
if (fields == null) {
|
||||
fields = List.copyOf(fieldsSupplier.get());
|
||||
fieldsSupplier = null;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -15,16 +15,17 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WasmTag {
|
||||
private List<WasmType> values = new ArrayList<>();
|
||||
public class WasmTag extends WasmEntity {
|
||||
private WasmFunctionType type;
|
||||
WasmModule module;
|
||||
int index;
|
||||
|
||||
public List<WasmType> getValues() {
|
||||
return values;
|
||||
public WasmTag(WasmFunctionType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public WasmFunctionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
* 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.
|
||||
|
@ -15,9 +15,52 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.model;
|
||||
|
||||
public enum WasmType {
|
||||
INT32,
|
||||
INT64,
|
||||
FLOAT32,
|
||||
FLOAT64
|
||||
public abstract class WasmType {
|
||||
public static final WasmType.Number INT32 = new Number(WasmNumType.INT32);
|
||||
public static final WasmType.Number INT64 = new Number(WasmNumType.INT64);
|
||||
public static final WasmType.Number FLOAT32 = new Number(WasmNumType.FLOAT32);
|
||||
public static final WasmType.Number FLOAT64 = new Number(WasmNumType.FLOAT64);
|
||||
|
||||
private WasmStorageType.Regular storageType;
|
||||
|
||||
private WasmType() {
|
||||
}
|
||||
|
||||
public WasmStorageType.Regular asStorage() {
|
||||
if (storageType == null) {
|
||||
storageType = new WasmStorageType.Regular(this);
|
||||
}
|
||||
return storageType;
|
||||
}
|
||||
|
||||
public static WasmType.Number num(WasmNumType number) {
|
||||
switch (number) {
|
||||
case INT32:
|
||||
return INT32;
|
||||
case INT64:
|
||||
return INT64;
|
||||
case FLOAT32:
|
||||
return FLOAT32;
|
||||
case FLOAT64:
|
||||
return FLOAT64;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Number extends WasmType {
|
||||
public final WasmNumType number;
|
||||
|
||||
private Number(WasmNumType number) {
|
||||
this.number = number;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Reference extends WasmType {
|
||||
public final WasmCompositeType composite;
|
||||
|
||||
Reference(WasmCompositeType composite) {
|
||||
this.composite = composite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,48 +19,33 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
|
||||
public class WasmCall extends WasmExpression {
|
||||
private String functionName;
|
||||
private boolean imported;
|
||||
private WasmFunction function;
|
||||
private List<WasmExpression> arguments = new ArrayList<>();
|
||||
|
||||
public WasmCall(String functionName, boolean imported) {
|
||||
Objects.requireNonNull(functionName);
|
||||
this.functionName = functionName;
|
||||
this.imported = imported;
|
||||
public WasmCall(WasmFunction function) {
|
||||
this.function = Objects.requireNonNull(function);
|
||||
}
|
||||
|
||||
public WasmCall(String functionName) {
|
||||
this(functionName, false);
|
||||
}
|
||||
|
||||
public WasmCall(String functionName, WasmExpression... arguments) {
|
||||
public WasmCall(WasmFunction functionName, WasmExpression... arguments) {
|
||||
this(functionName);
|
||||
getArguments().addAll(Arrays.asList(arguments));
|
||||
}
|
||||
|
||||
public String getFunctionName() {
|
||||
return functionName;
|
||||
public WasmFunction getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
public void setFunctionName(String functionName) {
|
||||
Objects.requireNonNull(functionName);
|
||||
this.functionName = functionName;
|
||||
public void setFunction(WasmFunction function) {
|
||||
this.function = Objects.requireNonNull(function);
|
||||
}
|
||||
|
||||
public List<WasmExpression> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public boolean isImported() {
|
||||
return imported;
|
||||
}
|
||||
|
||||
public void setImported(boolean imported) {
|
||||
this.imported = imported;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
|
|
@ -16,16 +16,16 @@
|
|||
package org.teavm.backend.wasm.model.expression;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
|
||||
public class WasmConversion extends WasmExpression {
|
||||
private WasmType sourceType;
|
||||
private WasmType targetType;
|
||||
private WasmNumType sourceType;
|
||||
private WasmNumType targetType;
|
||||
private boolean signed;
|
||||
private WasmExpression operand;
|
||||
private boolean reinterpret;
|
||||
|
||||
public WasmConversion(WasmType sourceType, WasmType targetType, boolean signed, WasmExpression operand) {
|
||||
public WasmConversion(WasmNumType sourceType, WasmNumType targetType, boolean signed, WasmExpression operand) {
|
||||
Objects.requireNonNull(sourceType);
|
||||
Objects.requireNonNull(targetType);
|
||||
Objects.requireNonNull(operand);
|
||||
|
@ -35,20 +35,20 @@ public class WasmConversion extends WasmExpression {
|
|||
this.operand = operand;
|
||||
}
|
||||
|
||||
public WasmType getSourceType() {
|
||||
public WasmNumType getSourceType() {
|
||||
return sourceType;
|
||||
}
|
||||
|
||||
public void setSourceType(WasmType sourceType) {
|
||||
public void setSourceType(WasmNumType sourceType) {
|
||||
Objects.requireNonNull(sourceType);
|
||||
this.sourceType = sourceType;
|
||||
}
|
||||
|
||||
public WasmType getTargetType() {
|
||||
public WasmNumType getTargetType() {
|
||||
return targetType;
|
||||
}
|
||||
|
||||
public void setTargetType(WasmType targetType) {
|
||||
public void setTargetType(WasmNumType targetType) {
|
||||
Objects.requireNonNull(targetType);
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,10 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmFloat64Constant expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmGetLocal expression) {
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@ public abstract class WasmExpression {
|
|||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
switch (type) {
|
||||
if (type instanceof WasmType.Number) {
|
||||
switch (((WasmType.Number) type).number) {
|
||||
case INT32:
|
||||
return new WasmInt32Constant(0);
|
||||
case INT64:
|
||||
|
@ -54,5 +55,10 @@ public abstract class WasmExpression {
|
|||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else if (type instanceof WasmType.Reference) {
|
||||
return new WasmNullConstant(((WasmType.Reference) type).composite);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ public interface WasmExpressionVisitor {
|
|||
|
||||
void visit(WasmFloat64Constant expression);
|
||||
|
||||
void visit(WasmNullConstant expression);
|
||||
|
||||
void visit(WasmGetLocal expression);
|
||||
|
||||
void visit(WasmSetLocal expression);
|
||||
|
|
|
@ -18,17 +18,16 @@ 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.WasmType;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
|
||||
public class WasmIndirectCall extends WasmExpression {
|
||||
private List<WasmType> parameterTypes = new ArrayList<>();
|
||||
private WasmType returnType;
|
||||
private WasmFunctionType type;
|
||||
private WasmExpression selector;
|
||||
private List<WasmExpression> arguments = new ArrayList<>();
|
||||
|
||||
public WasmIndirectCall(WasmExpression selector) {
|
||||
Objects.requireNonNull(selector);
|
||||
this.selector = selector;
|
||||
public WasmIndirectCall(WasmExpression selector, WasmFunctionType type) {
|
||||
this.selector = Objects.requireNonNull(selector);
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
public WasmExpression getSelector() {
|
||||
|
@ -36,26 +35,21 @@ public class WasmIndirectCall extends WasmExpression {
|
|||
}
|
||||
|
||||
public void setSelector(WasmExpression selector) {
|
||||
Objects.requireNonNull(selector);
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public List<WasmType> getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
public WasmType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
public void setReturnType(WasmType returnType) {
|
||||
this.returnType = returnType;
|
||||
this.selector = Objects.requireNonNull(selector);
|
||||
}
|
||||
|
||||
public List<WasmExpression> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public WasmFunctionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(WasmFunctionType type) {
|
||||
this.type = Objects.requireNonNull(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.backend.wasm.model.expression;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmCompositeType;
|
||||
|
||||
public class WasmNullConstant extends WasmExpression {
|
||||
public WasmCompositeType type;
|
||||
|
||||
public WasmNullConstant(WasmCompositeType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public WasmCompositeType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(WasmCompositeType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
|
@ -105,6 +105,10 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor {
|
|||
public void visit(WasmFloat64Constant expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmGetLocal expression) {
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class UnusedFunctionElimination {
|
|||
}
|
||||
|
||||
public void apply() {
|
||||
List<WasmFunction> exported = module.getFunctions().values().stream()
|
||||
List<WasmFunction> exported = module.functions.stream()
|
||||
.filter(function -> function.getExportName() != null)
|
||||
.collect(Collectors.toList());
|
||||
for (WasmFunction function : exported) {
|
||||
|
@ -48,11 +48,7 @@ public class UnusedFunctionElimination {
|
|||
use(module.getStartFunction());
|
||||
}
|
||||
|
||||
for (WasmFunction function : module.getFunctions().values().toArray(new WasmFunction[0])) {
|
||||
if (!usedFunctions.contains(function)) {
|
||||
module.remove(function);
|
||||
}
|
||||
}
|
||||
module.functions.removeIf(function -> !usedFunctions.contains(function));
|
||||
}
|
||||
|
||||
private void use(WasmFunction function) {
|
||||
|
@ -68,7 +64,7 @@ public class UnusedFunctionElimination {
|
|||
@Override
|
||||
public void visit(WasmCall expression) {
|
||||
super.visit(expression);
|
||||
WasmFunction function = module.getFunctions().get(expression.getFunctionName());
|
||||
var function = expression.getFunction();
|
||||
if (function != null) {
|
||||
use(function);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.optimization;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmCompositeType;
|
||||
import org.teavm.backend.wasm.model.WasmCompositeTypeVisitor;
|
||||
import org.teavm.backend.wasm.model.WasmDefaultCompositeTypeVisitor;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmStorageType;
|
||||
import org.teavm.backend.wasm.model.WasmStructure;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmDefaultExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
|
||||
public class UnusedTypeElimination {
|
||||
private WasmModule module;
|
||||
private Set<WasmCompositeType> usedTypes = new HashSet<>();
|
||||
|
||||
public UnusedTypeElimination(WasmModule module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public void apply() {
|
||||
collect();
|
||||
module.types.removeIf(type -> !usedTypes.contains(type));
|
||||
}
|
||||
|
||||
private void collect() {
|
||||
for (var function : module.functions) {
|
||||
useFrom(function);
|
||||
}
|
||||
for (var tag : module.tags) {
|
||||
use(tag.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private void useFrom(WasmFunction function) {
|
||||
use(function.getType());
|
||||
for (var part : function.getBody()) {
|
||||
part.acceptVisitor(exprVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
private void use(WasmCompositeType type) {
|
||||
if (!usedTypes.add(type)) {
|
||||
return;
|
||||
}
|
||||
type.acceptVisitor(typeVisitor);
|
||||
}
|
||||
|
||||
private WasmExpressionVisitor exprVisitor = new WasmDefaultExpressionVisitor() {
|
||||
@Override
|
||||
public void visit(WasmIndirectCall expression) {
|
||||
super.visit(expression);
|
||||
use(expression.getType());
|
||||
}
|
||||
};
|
||||
|
||||
private WasmCompositeTypeVisitor typeVisitor = new WasmDefaultCompositeTypeVisitor() {
|
||||
@Override
|
||||
public void visit(WasmStructure type) {
|
||||
for (var field : type.getFields()) {
|
||||
visit(field);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArray type) {
|
||||
visit(type.getElementType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionType type) {
|
||||
if (type.getReturnType() != null) {
|
||||
visit(type.getReturnType());
|
||||
}
|
||||
for (var parameter : type.getParameterTypes()) {
|
||||
visit(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
private void visit(WasmStorageType type) {
|
||||
if (type instanceof WasmStorageType.Regular) {
|
||||
visit(((WasmStorageType.Regular) type).type);
|
||||
}
|
||||
}
|
||||
|
||||
private void visit(WasmType type) {
|
||||
if (type instanceof WasmType.Reference) {
|
||||
use(((WasmType.Reference) type).composite);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.parser;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||
|
@ -97,7 +98,7 @@ public interface CodeListener {
|
|||
default void storeFloat64(int align, int offset) {
|
||||
}
|
||||
|
||||
default void convert(WasmType sourceType, WasmType targetType, boolean signed, boolean reinterpret) {
|
||||
default void convert(WasmNumType sourceType, WasmNumType targetType, boolean signed, boolean reinterpret) {
|
||||
}
|
||||
|
||||
default void memoryGrow() {
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.backend.wasm.parser;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmFloatType;
|
||||
|
@ -544,76 +545,76 @@ public class CodeSectionParser {
|
|||
break;
|
||||
|
||||
case 0xA7:
|
||||
codeListener.convert(WasmType.INT64, WasmType.INT32, false, false);
|
||||
codeListener.convert(WasmNumType.INT64, WasmNumType.INT32, false, false);
|
||||
break;
|
||||
case 0xA8:
|
||||
codeListener.convert(WasmType.FLOAT32, WasmType.INT32, false, false);
|
||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, false, false);
|
||||
break;
|
||||
case 0xA9:
|
||||
codeListener.convert(WasmType.FLOAT32, WasmType.INT32, true, false);
|
||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, true, false);
|
||||
break;
|
||||
case 0xAA:
|
||||
codeListener.convert(WasmType.FLOAT64, WasmType.INT32, false, false);
|
||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT32, false, false);
|
||||
break;
|
||||
case 0xAB:
|
||||
codeListener.convert(WasmType.FLOAT64, WasmType.INT32, true, false);
|
||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT32, true, false);
|
||||
break;
|
||||
case 0xAC:
|
||||
codeListener.convert(WasmType.INT32, WasmType.INT64, false, false);
|
||||
codeListener.convert(WasmNumType.INT32, WasmNumType.INT64, false, false);
|
||||
break;
|
||||
case 0xAD:
|
||||
codeListener.convert(WasmType.INT32, WasmType.INT64, true, false);
|
||||
codeListener.convert(WasmNumType.INT32, WasmNumType.INT64, true, false);
|
||||
break;
|
||||
case 0xAE:
|
||||
codeListener.convert(WasmType.FLOAT32, WasmType.INT64, false, false);
|
||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT64, false, false);
|
||||
break;
|
||||
case 0xAF:
|
||||
codeListener.convert(WasmType.FLOAT32, WasmType.INT64, true, false);
|
||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT64, true, false);
|
||||
break;
|
||||
case 0xB0:
|
||||
codeListener.convert(WasmType.FLOAT64, WasmType.INT64, false, false);
|
||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, false, false);
|
||||
break;
|
||||
case 0xB1:
|
||||
codeListener.convert(WasmType.FLOAT64, WasmType.INT64, true, false);
|
||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, true, false);
|
||||
break;
|
||||
case 0xB2:
|
||||
codeListener.convert(WasmType.INT32, WasmType.FLOAT32, false, false);
|
||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, false, false);
|
||||
break;
|
||||
case 0xB3:
|
||||
codeListener.convert(WasmType.INT32, WasmType.FLOAT32, true, false);
|
||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, true, false);
|
||||
break;
|
||||
case 0xB4:
|
||||
codeListener.convert(WasmType.INT64, WasmType.FLOAT32, false, false);
|
||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT32, false, false);
|
||||
break;
|
||||
case 0xB5:
|
||||
codeListener.convert(WasmType.INT64, WasmType.FLOAT32, true, false);
|
||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT32, true, false);
|
||||
break;
|
||||
case 0xB6:
|
||||
codeListener.convert(WasmType.FLOAT64, WasmType.FLOAT32, true, false);
|
||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.FLOAT32, true, false);
|
||||
break;
|
||||
case 0xB7:
|
||||
codeListener.convert(WasmType.INT32, WasmType.FLOAT64, false, false);
|
||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT64, false, false);
|
||||
break;
|
||||
case 0xB8:
|
||||
codeListener.convert(WasmType.INT32, WasmType.FLOAT64, true, false);
|
||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT64, true, false);
|
||||
break;
|
||||
case 0xB9:
|
||||
codeListener.convert(WasmType.INT64, WasmType.FLOAT64, false, false);
|
||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, false);
|
||||
break;
|
||||
case 0xBA:
|
||||
codeListener.convert(WasmType.INT64, WasmType.FLOAT64, true, false);
|
||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, true, false);
|
||||
break;
|
||||
case 0xBC:
|
||||
codeListener.convert(WasmType.FLOAT32, WasmType.INT32, false, true);
|
||||
codeListener.convert(WasmNumType.FLOAT32, WasmNumType.INT32, false, true);
|
||||
break;
|
||||
case 0xBD:
|
||||
codeListener.convert(WasmType.FLOAT64, WasmType.INT64, false, true);
|
||||
codeListener.convert(WasmNumType.FLOAT64, WasmNumType.INT64, false, true);
|
||||
break;
|
||||
case 0xBE:
|
||||
codeListener.convert(WasmType.INT32, WasmType.FLOAT32, false, true);
|
||||
codeListener.convert(WasmNumType.INT32, WasmNumType.FLOAT32, false, true);
|
||||
break;
|
||||
case 0xBF:
|
||||
codeListener.convert(WasmType.INT64, WasmType.FLOAT64, false, true);
|
||||
codeListener.convert(WasmNumType.INT64, WasmNumType.FLOAT64, false, true);
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
|
|
|
@ -18,9 +18,7 @@ package org.teavm.backend.wasm.render;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.backend.wasm.debug.DebugLines;
|
||||
|
@ -32,7 +30,6 @@ import org.teavm.backend.wasm.model.WasmFunction;
|
|||
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
|
||||
public class WasmBinaryRenderer {
|
||||
private static final int SECTION_UNKNOWN = 0;
|
||||
|
@ -53,9 +50,6 @@ public class WasmBinaryRenderer {
|
|||
|
||||
private WasmBinaryWriter output;
|
||||
private WasmBinaryVersion version;
|
||||
private List<WasmSignature> signatures = new ArrayList<>();
|
||||
private Map<WasmSignature, Integer> signatureIndexes = new HashMap<>();
|
||||
private Map<String, Integer> functionIndexes = new HashMap<>();
|
||||
private boolean obfuscated;
|
||||
private DwarfGenerator dwarfGenerator;
|
||||
private DwarfClassGenerator dwarfClassGen;
|
||||
|
@ -88,7 +82,7 @@ public class WasmBinaryRenderer {
|
|||
break;
|
||||
}
|
||||
|
||||
renderSignatures(module);
|
||||
renderTypes(module);
|
||||
renderImports(module);
|
||||
renderFunctions(module);
|
||||
renderTable(module);
|
||||
|
@ -105,33 +99,13 @@ public class WasmBinaryRenderer {
|
|||
renderCustomSections(module, customSectionSupplier);
|
||||
}
|
||||
|
||||
private void renderSignatures(WasmModule module) {
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
WasmSignatureCollector signatureCollector = new WasmSignatureCollector(this::registerSignature);
|
||||
private void renderTypes(WasmModule module) {
|
||||
var section = new WasmBinaryWriter();
|
||||
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
registerSignature(WasmSignature.fromFunction(function));
|
||||
for (WasmExpression part : function.getBody()) {
|
||||
part.acceptVisitor(signatureCollector);
|
||||
}
|
||||
}
|
||||
for (var tag : module.getTags()) {
|
||||
registerSignature(WasmSignature.fromTag(tag));
|
||||
}
|
||||
|
||||
section.writeLEB(signatures.size());
|
||||
for (WasmSignature signature : signatures) {
|
||||
section.writeByte(0x60);
|
||||
section.writeLEB(signature.types.length - 1);
|
||||
for (int i = 1; i < signature.types.length; ++i) {
|
||||
section.writeType(signature.types[i], version);
|
||||
}
|
||||
if (signature.types[0] != null) {
|
||||
section.writeByte(1);
|
||||
section.writeType(signature.types[0], version);
|
||||
} else {
|
||||
section.writeByte(0);
|
||||
}
|
||||
var typeRenderer = new WasmCompositeTypeBinaryRenderer(module, section);
|
||||
section.writeLEB(module.types.size());
|
||||
for (var type : module.types) {
|
||||
type.acceptVisitor(typeRenderer);
|
||||
}
|
||||
|
||||
writeSection(SECTION_TYPE, "type", section.getData());
|
||||
|
@ -139,11 +113,10 @@ public class WasmBinaryRenderer {
|
|||
|
||||
private void renderImports(WasmModule module) {
|
||||
List<WasmFunction> functions = new ArrayList<>();
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (var function : module.functions) {
|
||||
if (function.getImportName() == null) {
|
||||
continue;
|
||||
}
|
||||
functionIndexes.put(function.getName(), functions.size());
|
||||
functions.add(function);
|
||||
}
|
||||
if (functions.isEmpty()) {
|
||||
|
@ -154,9 +127,7 @@ public class WasmBinaryRenderer {
|
|||
|
||||
section.writeLEB(functions.size());
|
||||
for (WasmFunction function : functions) {
|
||||
WasmSignature signature = WasmSignature.fromFunction(function);
|
||||
int signatureIndex = signatureIndexes.get(signature);
|
||||
|
||||
int signatureIndex = module.types.indexOf(function.getType());
|
||||
String moduleName = function.getImportModule();
|
||||
if (moduleName == null) {
|
||||
moduleName = "";
|
||||
|
@ -175,17 +146,13 @@ public class WasmBinaryRenderer {
|
|||
private void renderFunctions(WasmModule module) {
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
List<WasmFunction> functions = module.getFunctions().values().stream()
|
||||
List<WasmFunction> functions = module.functions.stream()
|
||||
.filter(function -> function.getImportName() == null)
|
||||
.collect(Collectors.toList());
|
||||
for (WasmFunction function : functions) {
|
||||
functionIndexes.put(function.getName(), functionIndexes.size());
|
||||
}
|
||||
|
||||
section.writeLEB(functions.size());
|
||||
for (WasmFunction function : functions) {
|
||||
WasmSignature signature = WasmSignature.fromFunction(function);
|
||||
section.writeLEB(signatureIndexes.get(signature));
|
||||
for (var function : functions) {
|
||||
section.writeLEB(module.types.indexOf(function.getType()));
|
||||
}
|
||||
|
||||
writeSection(SECTION_FUNCTION, "function", section.getData());
|
||||
|
@ -201,7 +168,7 @@ public class WasmBinaryRenderer {
|
|||
section.writeByte(1);
|
||||
section.writeByte(0x70);
|
||||
section.writeByte(0);
|
||||
section.writeLEB(functionIndexes.size());
|
||||
section.writeLEB(module.functions.size());
|
||||
|
||||
writeSection(SECTION_TABLE, "table", section.getData());
|
||||
}
|
||||
|
@ -223,13 +190,13 @@ public class WasmBinaryRenderer {
|
|||
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
List<WasmFunction> functions = module.getFunctions().values().stream()
|
||||
List<WasmFunction> functions = module.functions.stream()
|
||||
.filter(function -> function.getExportName() != null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
section.writeLEB(functions.size() + 1);
|
||||
for (WasmFunction function : functions) {
|
||||
int functionIndex = functionIndexes.get(function.getName());
|
||||
for (var function : functions) {
|
||||
int functionIndex = module.functions.indexOf(function);
|
||||
|
||||
section.writeAsciiString(function.getExportName());
|
||||
|
||||
|
@ -251,7 +218,7 @@ public class WasmBinaryRenderer {
|
|||
}
|
||||
|
||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
section.writeLEB(functionIndexes.get(module.getStartFunction().getName()));
|
||||
section.writeLEB(module.functions.indexOf(module.getStartFunction()));
|
||||
|
||||
writeSection(SECTION_START, "start", section.getData());
|
||||
}
|
||||
|
@ -268,8 +235,8 @@ public class WasmBinaryRenderer {
|
|||
renderInitializer(section, 0);
|
||||
|
||||
section.writeLEB(module.getFunctionTable().size());
|
||||
for (WasmFunction function : module.getFunctionTable()) {
|
||||
section.writeLEB(functionIndexes.get(function.getName()));
|
||||
for (var function : module.getFunctionTable()) {
|
||||
section.writeLEB(module.functions.indexOf(function));
|
||||
}
|
||||
|
||||
writeSection(SECTION_ELEMENT, "element", section.getData());
|
||||
|
@ -278,13 +245,13 @@ public class WasmBinaryRenderer {
|
|||
private void renderCode(WasmModule module) {
|
||||
var section = new WasmBinaryWriter();
|
||||
|
||||
var functions = module.getFunctions().values().stream()
|
||||
var functions = module.functions.stream()
|
||||
.filter(function -> function.getImportName() == null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
section.writeLEB(functions.size());
|
||||
for (var function : functions) {
|
||||
var body = renderFunction(function, section.getPosition() + 4);
|
||||
var body = renderFunction(module, function, section.getPosition() + 4);
|
||||
var startPos = section.getPosition();
|
||||
section.writeLEB4(body.length);
|
||||
section.writeBytes(body);
|
||||
|
@ -301,7 +268,7 @@ public class WasmBinaryRenderer {
|
|||
writeSection(SECTION_CODE, "code", section.getData());
|
||||
}
|
||||
|
||||
private byte[] renderFunction(WasmFunction function, int offset) {
|
||||
private byte[] renderFunction(WasmModule module, WasmFunction function, int offset) {
|
||||
var code = new WasmBinaryWriter();
|
||||
|
||||
var dwarfSubprogram = dwarfClassGen != null ? dwarfClassGen.getSubprogram(function.getName()) : null;
|
||||
|
@ -314,7 +281,7 @@ public class WasmBinaryRenderer {
|
|||
}
|
||||
|
||||
var localVariables = function.getLocalVariables();
|
||||
int parameterCount = Math.min(function.getParameters().size(), localVariables.size());
|
||||
int parameterCount = Math.min(function.getType().getParameterTypes().size(), localVariables.size());
|
||||
localVariables = localVariables.subList(parameterCount, localVariables.size());
|
||||
if (localVariables.isEmpty()) {
|
||||
code.writeLEB(0);
|
||||
|
@ -335,13 +302,12 @@ public class WasmBinaryRenderer {
|
|||
code.writeLEB(localEntries.size());
|
||||
for (var entry : localEntries) {
|
||||
code.writeLEB(entry.count);
|
||||
code.writeType(entry.type, version);
|
||||
code.writeType(entry.type, module);
|
||||
}
|
||||
}
|
||||
|
||||
var importIndexes = this.functionIndexes;
|
||||
var visitor = new WasmBinaryRenderingVisitor(code, version, functionIndexes, importIndexes,
|
||||
signatureIndexes, dwarfGenerator, function.getJavaMethod() != null ? debugLines : null, offset);
|
||||
var visitor = new WasmBinaryRenderingVisitor(code, module, dwarfGenerator,
|
||||
function.getJavaMethod() != null ? debugLines : null, offset);
|
||||
for (var part : function.getBody()) {
|
||||
part.acceptVisitor(visitor);
|
||||
}
|
||||
|
@ -400,15 +366,15 @@ public class WasmBinaryRenderer {
|
|||
}
|
||||
|
||||
private void renderTags(WasmModule module) {
|
||||
if (module.getTags().isEmpty()) {
|
||||
if (module.tags.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var section = new WasmBinaryWriter();
|
||||
section.writeLEB(module.getTags().size());
|
||||
for (var tag : module.getTags()) {
|
||||
section.writeLEB(module.tags.size());
|
||||
for (var tag : module.tags) {
|
||||
section.writeByte(0);
|
||||
section.writeLEB(signatureIndexes.get(WasmSignature.fromTag(tag)));
|
||||
section.writeLEB(module.types.indexOf(tag.getType()));
|
||||
}
|
||||
|
||||
writeSection(SECTION_TAGS, "tags", section.getData());
|
||||
|
@ -418,12 +384,13 @@ public class WasmBinaryRenderer {
|
|||
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||
|
||||
WasmBinaryWriter functionsSubsection = new WasmBinaryWriter();
|
||||
Collection<WasmFunction> functions = module.getFunctions().values();
|
||||
functions = functions.stream().filter(f -> f.getImportName() == null).collect(Collectors.toList());
|
||||
var functions = module.functions.stream()
|
||||
.filter(f -> f.getName() != null && f.getImportName() == null)
|
||||
.collect(Collectors.toList());
|
||||
functionsSubsection.writeLEB(functions.size());
|
||||
|
||||
for (WasmFunction function : functions) {
|
||||
functionsSubsection.writeLEB(functionIndexes.get(function.getName()));
|
||||
functionsSubsection.writeLEB(module.functions.indexOf(function));
|
||||
functionsSubsection.writeAsciiString(function.getName());
|
||||
}
|
||||
|
||||
|
@ -460,14 +427,6 @@ public class WasmBinaryRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
private void registerSignature(WasmSignature signature) {
|
||||
signatureIndexes.computeIfAbsent(signature, key -> {
|
||||
int result = signatures.size();
|
||||
signatures.add(key);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
private void writeSection(int id, String name, byte[] data) {
|
||||
var start = output.getPosition();
|
||||
output.writeByte(id);
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
import org.teavm.backend.wasm.debug.DebugLines;
|
||||
import org.teavm.backend.wasm.generate.DwarfGenerator;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -50,6 +51,7 @@ import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
|
|||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmMemoryGrow;
|
||||
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreFloat32;
|
||||
|
@ -65,10 +67,7 @@ import org.teavm.model.TextLocation;
|
|||
|
||||
class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
||||
private WasmBinaryWriter writer;
|
||||
private WasmBinaryVersion version;
|
||||
private Map<String, Integer> functionIndexes;
|
||||
private Map<String, Integer> importedIndexes;
|
||||
private Map<WasmSignature, Integer> signatureIndexes;
|
||||
private WasmModule module;
|
||||
private DwarfGenerator dwarfGenerator;
|
||||
private DebugLines debugLines;
|
||||
private int addressOffset;
|
||||
|
@ -82,14 +81,10 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
private int positionToEmit;
|
||||
private List<TextLocation> locationStack = new ArrayList<>();
|
||||
|
||||
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmBinaryVersion version, Map<String, Integer> functionIndexes,
|
||||
Map<String, Integer> importedIndexes, Map<WasmSignature, Integer> signatureIndexes,
|
||||
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmModule module,
|
||||
DwarfGenerator dwarfGenerator, DebugLines debugLines, int addressOffset) {
|
||||
this.writer = writer;
|
||||
this.version = version;
|
||||
this.functionIndexes = functionIndexes;
|
||||
this.importedIndexes = importedIndexes;
|
||||
this.signatureIndexes = signatureIndexes;
|
||||
this.module = module;
|
||||
this.dwarfGenerator = dwarfGenerator;
|
||||
this.addressOffset = addressOffset;
|
||||
this.debugLines = debugLines;
|
||||
|
@ -115,7 +110,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
|
||||
private void writeBlockType(WasmType type) {
|
||||
writer.writeType(type, version);
|
||||
writer.writeType(type, module);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -240,6 +235,14 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
popLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
pushLocation(expression);
|
||||
writer.writeByte(0xD0);
|
||||
writer.writeSignedLEB(module.types.indexOf(expression.getType()));
|
||||
popLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmGetLocal expression) {
|
||||
pushLocation(expression);
|
||||
|
@ -724,13 +727,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
for (WasmExpression argument : expression.getArguments()) {
|
||||
argument.acceptVisitor(this);
|
||||
}
|
||||
Integer functionIndex = !expression.isImported()
|
||||
? functionIndexes.get(expression.getFunctionName())
|
||||
: importedIndexes.get(expression.getFunctionName());
|
||||
if (functionIndex == null) {
|
||||
writer.writeByte(0x00);
|
||||
return;
|
||||
}
|
||||
var functionIndex = module.functions.indexOf(expression.getFunction());
|
||||
|
||||
writer.writeByte(0x10);
|
||||
writer.writeLEB(functionIndex);
|
||||
|
@ -745,13 +742,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
expression.getSelector().acceptVisitor(this);
|
||||
writer.writeByte(0x11);
|
||||
|
||||
WasmType[] signatureTypes = new WasmType[expression.getParameterTypes().size() + 1];
|
||||
signatureTypes[0] = expression.getReturnType();
|
||||
for (int i = 0; i < expression.getParameterTypes().size(); ++i) {
|
||||
signatureTypes[i + 1] = expression.getParameterTypes().get(i);
|
||||
}
|
||||
writer.writeLEB(signatureIndexes.get(new WasmSignature(signatureTypes)));
|
||||
writer.writeLEB(module.types.indexOf(expression.getType()));
|
||||
|
||||
writer.writeByte(0);
|
||||
popLocation();
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
package org.teavm.backend.wasm.render;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
||||
public class WasmBinaryWriter {
|
||||
|
@ -27,11 +29,19 @@ public class WasmBinaryWriter {
|
|||
data[pointer++] = (byte) v;
|
||||
}
|
||||
|
||||
public void writeType(WasmType type, WasmBinaryVersion version) {
|
||||
public void writeType(WasmType type, WasmModule module) {
|
||||
if (type == null) {
|
||||
writeByte(0x40);
|
||||
return;
|
||||
}
|
||||
if (type instanceof WasmType.Number) {
|
||||
writeType(((WasmType.Number) type).number);
|
||||
} else if (type instanceof WasmType.Reference) {
|
||||
writeSignedLEB(module.types.indexOf(((WasmType.Reference) type).composite));
|
||||
}
|
||||
}
|
||||
|
||||
public void writeType(WasmNumType type) {
|
||||
switch (type) {
|
||||
case INT32:
|
||||
writeByte(0x7F);
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.teavm.backend.wasm.model.expression.WasmExpression;
|
|||
import org.teavm.model.TextLocation;
|
||||
|
||||
public class WasmCRenderer {
|
||||
private WasmModule module;
|
||||
private StringBuilder out = new StringBuilder();
|
||||
private int indentLevel;
|
||||
String currentFile = "";
|
||||
|
@ -37,6 +38,10 @@ public class WasmCRenderer {
|
|||
boolean memoryAccessChecked;
|
||||
TextLocation lastReportedLocation;
|
||||
|
||||
public WasmCRenderer(WasmModule module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public boolean isLineNumbersEmitted() {
|
||||
return lineNumbersEmitted;
|
||||
}
|
||||
|
@ -75,7 +80,7 @@ public class WasmCRenderer {
|
|||
renderFunctionDeclarations(module);
|
||||
renderFunctionTable(module);
|
||||
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (var function : module.functions) {
|
||||
if (function.getImportName() == null) {
|
||||
renderFunction(function);
|
||||
}
|
||||
|
@ -91,13 +96,13 @@ public class WasmCRenderer {
|
|||
line(module.getStartFunction().getName() + "();");
|
||||
}
|
||||
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (var function : module.functions) {
|
||||
if (function.getExportName() != null && function.getExportName().equals("main")) {
|
||||
line(function.getName() + "(1);");
|
||||
}
|
||||
}
|
||||
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (var function : module.functions) {
|
||||
if (Objects.equals(function.getExportName(), "_start")) {
|
||||
line(function.getName() + "();");
|
||||
}
|
||||
|
@ -171,26 +176,26 @@ public class WasmCRenderer {
|
|||
}
|
||||
|
||||
private void renderFunctionDeclarations(WasmModule module) {
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (var function : module.functions) {
|
||||
line(functionDeclaration(function) + ";");
|
||||
}
|
||||
}
|
||||
|
||||
private void renderFunction(WasmFunction function) {
|
||||
WasmCRenderingVisitor visitor = new WasmCRenderingVisitor(function.getResult(),
|
||||
function.getLocalVariables().size(), function.getModule());
|
||||
var visitor = new WasmCRenderingVisitor(function.getType().getReturnType(),
|
||||
function.getLocalVariables().size(), module);
|
||||
visitor.setMemoryAccessChecked(memoryAccessChecked);
|
||||
|
||||
StringBuilder declaration = new StringBuilder();
|
||||
renderFunctionModifiers(declaration, function);
|
||||
declaration.append(WasmCRenderingVisitor.mapType(function.getResult())).append(' ');
|
||||
declaration.append(WasmCRenderingVisitor.mapType(function.getType().getReturnType())).append(' ');
|
||||
declaration.append(function.getName()).append('(');
|
||||
int sz = Math.min(function.getParameters().size(), function.getLocalVariables().size());
|
||||
int sz = Math.min(function.getType().getParameterTypes().size(), function.getLocalVariables().size());
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (i > 0) {
|
||||
declaration.append(", ");
|
||||
}
|
||||
declaration.append(WasmCRenderingVisitor.mapType(function.getParameters().get(i)));
|
||||
declaration.append(WasmCRenderingVisitor.mapType(function.getType().getParameterTypes().get(i)));
|
||||
WasmLocal var = function.getLocalVariables().get(i);
|
||||
declaration.append(' ').append(visitor.getVariableName(var));
|
||||
}
|
||||
|
@ -212,7 +217,7 @@ public class WasmCRenderer {
|
|||
lines.addAll(visitor.getValue().getLines());
|
||||
}
|
||||
|
||||
visitor.setRequiredType(function.getResult());
|
||||
visitor.setRequiredType(function.getType().getReturnType());
|
||||
body.get(body.size() - 1).acceptVisitor(visitor);
|
||||
lines.addAll(visitor.getValue().getLines());
|
||||
if (visitor.getValue().getText() != null) {
|
||||
|
@ -232,7 +237,7 @@ public class WasmCRenderer {
|
|||
private String functionDeclaration(WasmFunction function) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
renderFunctionModifiers(sb, function);
|
||||
sb.append(WasmCRenderingVisitor.mapType(function.getResult())).append(' ');
|
||||
sb.append(WasmCRenderingVisitor.mapType(function.getType().getReturnType())).append(' ');
|
||||
if (function.getImportName() != null) {
|
||||
sb.append(function.getImportModule() != null && !function.getImportModule().isEmpty()
|
||||
? function.getImportModule() + "_" + function.getImportName()
|
||||
|
@ -241,11 +246,11 @@ public class WasmCRenderer {
|
|||
sb.append(function.getName());
|
||||
}
|
||||
sb.append("(");
|
||||
for (int i = 0; i < function.getParameters().size(); ++i) {
|
||||
for (int i = 0; i < function.getType().getParameterTypes().size(); ++i) {
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(WasmCRenderingVisitor.mapType(function.getParameters().get(i)));
|
||||
sb.append(WasmCRenderingVisitor.mapType(function.getType().getParameterTypes().get(i)));
|
||||
}
|
||||
sb.append(")");
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -54,6 +54,7 @@ import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
|
|||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmMemoryGrow;
|
||||
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreFloat32;
|
||||
|
@ -333,6 +334,11 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
value = CExpression.relocatable("/* can't produce ref.null */");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmGetLocal expression) {
|
||||
value = new CExpression(getVariableName(expression.getLocal()));
|
||||
|
@ -647,7 +653,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
if (type != null && expression.getSourceType() != expression.getTargetType()) {
|
||||
switch (expression.getTargetType()) {
|
||||
case INT32:
|
||||
if (expression.getSourceType() == WasmType.FLOAT32 && expression.isReinterpret()) {
|
||||
if (expression.getSourceType() == WasmNumType.FLOAT32 && expression.isReinterpret()) {
|
||||
result.setText("reinterpret_float32(" + operand.getText() + ")");
|
||||
} else if (expression.isSigned()) {
|
||||
result.setText("(int32_t) " + operand.getText());
|
||||
|
@ -656,7 +662,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
break;
|
||||
case INT64:
|
||||
if (expression.getSourceType() == WasmType.FLOAT64 && expression.isReinterpret()) {
|
||||
if (expression.getSourceType() == WasmNumType.FLOAT64 && expression.isReinterpret()) {
|
||||
result.setText("reinterpret_float64(" + operand.getText() + ")");
|
||||
} else if (expression.isSigned()) {
|
||||
result.setText("(int64_t) " + operand.getText());
|
||||
|
@ -665,9 +671,9 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
break;
|
||||
case FLOAT32:
|
||||
if (expression.getSourceType() == WasmType.INT32 && expression.isReinterpret()) {
|
||||
if (expression.getSourceType() == WasmNumType.INT32 && expression.isReinterpret()) {
|
||||
result.setText("reinterpret_int32(" + operand.getText() + ")");
|
||||
} else if (expression.getSourceType() == WasmType.FLOAT64) {
|
||||
} else if (expression.getSourceType() == WasmNumType.FLOAT64) {
|
||||
result.setText("(float) " + operand.getText());
|
||||
} else if (expression.isSigned()) {
|
||||
result.setText("(float) (int64_t) " + operand.getText());
|
||||
|
@ -676,9 +682,9 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
break;
|
||||
case FLOAT64:
|
||||
if (expression.getSourceType() == WasmType.INT64 && expression.isReinterpret()) {
|
||||
if (expression.getSourceType() == WasmNumType.INT64 && expression.isReinterpret()) {
|
||||
result.setText("reinterpret_int64(" + operand.getText() + ")");
|
||||
} else if (expression.getSourceType() == WasmType.FLOAT32) {
|
||||
} else if (expression.getSourceType() == WasmNumType.FLOAT32) {
|
||||
result.setText("(double) " + operand.getText());
|
||||
} else if (expression.isSigned()) {
|
||||
result.setText("(double) (int64_t) " + operand.getText());
|
||||
|
@ -694,25 +700,18 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmCall expression) {
|
||||
WasmFunction function = module.getFunctions().get(expression.getFunctionName());
|
||||
if (function == null) {
|
||||
value = new CExpression("0");
|
||||
return;
|
||||
}
|
||||
var function = expression.getFunction();
|
||||
|
||||
CExpression result = new CExpression();
|
||||
WasmType type = requiredType;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (expression.isImported()) {
|
||||
sb.append(function.getImportModule() != null && !function.getImportModule().isEmpty()
|
||||
? function.getImportModule() + "_" + function.getImportName()
|
||||
: function.getImportName());
|
||||
} else {
|
||||
sb.append(expression.getFunctionName());
|
||||
}
|
||||
|
||||
sb.append('(');
|
||||
translateArguments(expression.getArguments(), function.getParameters(), result, sb);
|
||||
translateArguments(expression.getArguments(), function.getType().getParameterTypes(), result, sb);
|
||||
sb.append(')');
|
||||
result.setText(sb.toString());
|
||||
|
||||
|
@ -729,12 +728,12 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
WasmType type = requiredType;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("(*(" + mapType(expression.getReturnType()) + " (*)(");
|
||||
for (int i = 0; i < expression.getParameterTypes().size(); ++i) {
|
||||
sb.append("(*(" + mapType(expression.getType().getReturnType()) + " (*)(");
|
||||
for (int i = 0; i < expression.getType().getParameterTypes().size(); ++i) {
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(mapType(expression.getParameterTypes().get(i)));
|
||||
sb.append(mapType(expression.getType().getParameterTypes().get(i)));
|
||||
}
|
||||
sb.append(")) ");
|
||||
|
||||
|
@ -743,7 +742,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
result.getLines().addAll(value.getLines());
|
||||
value = cacheIfNeeded(WasmType.INT32, value, result);
|
||||
sb.append("wasm_table[" + value.getText() + "])(");
|
||||
translateArguments(expression.getArguments(), expression.getParameterTypes(), result, sb);
|
||||
translateArguments(expression.getArguments(), expression.getType().getParameterTypes(), result, sb);
|
||||
sb.append(")");
|
||||
result.setText(sb.toString());
|
||||
|
||||
|
@ -754,7 +753,7 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
value = result;
|
||||
}
|
||||
|
||||
private void translateArguments(List<WasmExpression> wasmArguments, List<WasmType> signature,
|
||||
private void translateArguments(List<? extends WasmExpression> wasmArguments, List<? extends WasmType> signature,
|
||||
CExpression result, StringBuilder sb) {
|
||||
if (wasmArguments.isEmpty()) {
|
||||
return;
|
||||
|
@ -1148,9 +1147,18 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
|
||||
static String mapType(WasmType type) {
|
||||
if (type == null) {
|
||||
if (type instanceof WasmType.Number) {
|
||||
return mapType(((WasmType.Number) type).number);
|
||||
} else if (type instanceof WasmType.Reference) {
|
||||
return "/* unknown type */";
|
||||
} else if (type == null) {
|
||||
return "void";
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
static String mapType(WasmNumType type) {
|
||||
switch (type) {
|
||||
case INT32:
|
||||
return "int32_t";
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.render;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmArray;
|
||||
import org.teavm.backend.wasm.model.WasmCompositeTypeVisitor;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmStructure;
|
||||
|
||||
public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor {
|
||||
private WasmModule module;
|
||||
private WasmBinaryWriter section;
|
||||
|
||||
public WasmCompositeTypeBinaryRenderer(WasmModule module, WasmBinaryWriter section) {
|
||||
this.section = section;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmStructure type) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmArray type) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmFunctionType type) {
|
||||
section.writeByte(0x60);
|
||||
section.writeLEB(type.getParameterTypes().size());
|
||||
for (var inputType : type.getParameterTypes()) {
|
||||
section.writeType(inputType, module);
|
||||
}
|
||||
if (type.getReturnType() != null) {
|
||||
section.writeByte(1);
|
||||
section.writeType(type.getReturnType(), module);
|
||||
} else {
|
||||
section.writeByte(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,13 @@ import org.teavm.backend.wasm.model.WasmModule;
|
|||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
|
||||
public class WasmRenderer {
|
||||
private WasmRenderingVisitor visitor = new WasmRenderingVisitor();
|
||||
private WasmRenderingVisitor visitor;
|
||||
private WasmModule module;
|
||||
|
||||
public WasmRenderer(WasmModule module) {
|
||||
visitor = new WasmRenderingVisitor(module);
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public WasmRenderer append(String text) {
|
||||
visitor.append(text);
|
||||
|
@ -58,12 +64,12 @@ public class WasmRenderer {
|
|||
renderTypes(module);
|
||||
|
||||
int functionIndex = 0;
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (WasmFunction function : module.functions) {
|
||||
if (function.getImportName() != null) {
|
||||
lf().append(";; function #" + functionIndex++).lf().render(function);
|
||||
}
|
||||
}
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (WasmFunction function : module.functions) {
|
||||
if (function.getImportName() == null) {
|
||||
lf().append(";; function #" + functionIndex++).lf().render(function);
|
||||
}
|
||||
|
@ -127,7 +133,7 @@ public class WasmRenderer {
|
|||
|
||||
renderSignature(function);
|
||||
|
||||
int firstLocalVariable = function.getParameters().size();
|
||||
int firstLocalVariable = function.getType().getParameterTypes().size();
|
||||
if (firstLocalVariable < function.getLocalVariables().size()) {
|
||||
visitor.lf().open().append("local");
|
||||
List<WasmLocal> locals = function.getLocalVariables().subList(firstLocalVariable,
|
||||
|
@ -148,44 +154,10 @@ public class WasmRenderer {
|
|||
}
|
||||
|
||||
private void renderSignature(WasmFunction function) {
|
||||
WasmSignature signature = WasmSignature.fromFunction(function);
|
||||
visitor.append(" ").open().append("type $type" + visitor.getSignatureIndex(signature)).close();
|
||||
visitor.append(" ").open().append("type $type" + module.types.indexOf(function.getType())).close();
|
||||
}
|
||||
|
||||
private void renderTypes(WasmModule module) {
|
||||
WasmSignatureCollector signatureCollector = new WasmSignatureCollector(visitor::getSignatureIndex);
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
visitor.getSignatureIndex(WasmSignature.fromFunction(function));
|
||||
for (WasmExpression part : function.getBody()) {
|
||||
part.acceptVisitor(signatureCollector);
|
||||
}
|
||||
}
|
||||
|
||||
if (visitor.signatureList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
visitor.lf();
|
||||
int index = 0;
|
||||
for (WasmSignature signature : visitor.signatureList) {
|
||||
visitor.open().append("type $type" + index++ + " ");
|
||||
visitor.open().append("func");
|
||||
if (signature.types.length > 1) {
|
||||
visitor.append(" ").open().append("param");
|
||||
for (int i = 1; i < signature.types.length; ++i) {
|
||||
visitor.append(" ").append(signature.types[i]);
|
||||
}
|
||||
visitor.close();
|
||||
}
|
||||
if (signature.types[0] != null) {
|
||||
visitor.append(" ").open().append("result ");
|
||||
visitor.append(signature.types[0]);
|
||||
visitor.close();
|
||||
}
|
||||
visitor.close();
|
||||
visitor.close();
|
||||
visitor.lf();
|
||||
}
|
||||
}
|
||||
|
||||
private void renderTable(WasmModule module) {
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmNumType;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -54,6 +54,7 @@ import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
|
|||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmMemoryGrow;
|
||||
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreFloat32;
|
||||
|
@ -71,8 +72,11 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
private int indentLevel;
|
||||
private boolean lfDeferred;
|
||||
boolean lineNumbersEmitted;
|
||||
List<WasmSignature> signatureList = new ArrayList<>();
|
||||
private Map<WasmSignature, Integer> signatureMap = new HashMap<>();
|
||||
WasmModule module;
|
||||
|
||||
WasmRenderingVisitor(WasmModule module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
void preprocess(WasmExpression expression) {
|
||||
expression.acceptVisitor(new WasmDefaultExpressionVisitor() {
|
||||
|
@ -269,6 +273,11 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
open().append("f64.const " + Double.toHexString(expression.getValue())).close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
open().append("ref.null " + module.types.indexOf(expression.getType())).close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmGetLocal expression) {
|
||||
open().append("get_local " + asString(expression.getLocal())).close();
|
||||
|
@ -398,7 +407,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmCall expression) {
|
||||
open().append("call").append(" $" + expression.getFunctionName());
|
||||
open().append("call").append(" $" + module.functions.indexOf(expression.getFunction()));
|
||||
for (WasmExpression argument : expression.getArguments()) {
|
||||
line(argument);
|
||||
}
|
||||
|
@ -407,25 +416,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmIndirectCall expression) {
|
||||
WasmType[] types = new WasmType[expression.getParameterTypes().size() + 1];
|
||||
types[0] = expression.getReturnType();
|
||||
for (int i = 0; i < expression.getParameterTypes().size(); ++i) {
|
||||
types[i + 1] = expression.getParameterTypes().get(i);
|
||||
}
|
||||
|
||||
open().append("call_indirect").append(" $type" + getSignatureIndex(new WasmSignature(types)));
|
||||
line(expression.getSelector());
|
||||
for (WasmExpression argument : expression.getArguments()) {
|
||||
line(argument);
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
int getSignatureIndex(WasmSignature signature) {
|
||||
return signatureMap.computeIfAbsent(signature, key -> {
|
||||
signatureList.add(key);
|
||||
return signatureMap.size();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -654,6 +645,16 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
|||
}
|
||||
|
||||
private String type(WasmType type) {
|
||||
if (type instanceof WasmType.Number) {
|
||||
return type(((WasmType.Number) type).number);
|
||||
} else if (type instanceof WasmType.Reference) {
|
||||
return "(ref " + module.types.indexOf(((WasmType.Reference) type).composite) + ")";
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private String type(WasmNumType type) {
|
||||
switch (type) {
|
||||
case INT32:
|
||||
return "i32";
|
||||
|
|
|
@ -15,16 +15,25 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.render;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmTag;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
||||
final class WasmSignature {
|
||||
WasmType[] types;
|
||||
public final class WasmSignature {
|
||||
private WasmType returnType;
|
||||
private List<? extends WasmType> types;
|
||||
|
||||
WasmSignature(WasmType[] types) {
|
||||
this.types = types;
|
||||
public WasmSignature(WasmType returnType, WasmType... parameterTypes) {
|
||||
this.returnType = returnType;
|
||||
this.types = List.of(parameterTypes);
|
||||
}
|
||||
|
||||
public WasmType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
public List<? extends WasmType> getParameterTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -36,28 +45,11 @@ final class WasmSignature {
|
|||
return false;
|
||||
}
|
||||
WasmSignature that = (WasmSignature) o;
|
||||
return Arrays.equals(types, that.types);
|
||||
return Objects.equals(types, that.types) && Objects.equals(returnType, that.returnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(types);
|
||||
}
|
||||
|
||||
static WasmSignature fromFunction(WasmFunction function) {
|
||||
WasmType[] types = new WasmType[function.getParameters().size() + 1];
|
||||
types[0] = function.getResult();
|
||||
for (int i = 0; i < function.getParameters().size(); ++i) {
|
||||
types[i + 1] = function.getParameters().get(i);
|
||||
}
|
||||
return new WasmSignature(types);
|
||||
}
|
||||
|
||||
static WasmSignature fromTag(WasmTag tag) {
|
||||
var types = new WasmType[tag.getValues().size() + 1];
|
||||
for (var i = 0; i < tag.getValues().size(); i++) {
|
||||
types[i + 1] = tag.getValues().get(i);
|
||||
}
|
||||
return new WasmSignature(types);
|
||||
return Objects.hash(types, returnType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 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.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmDefaultExpressionVisitor;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIndirectCall;
|
||||
|
||||
class WasmSignatureCollector extends WasmDefaultExpressionVisitor {
|
||||
private Consumer<WasmSignature> consumer;
|
||||
|
||||
public WasmSignatureCollector(Consumer<WasmSignature> consumer) {
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIndirectCall expression) {
|
||||
WasmType[] types = new WasmType[expression.getParameterTypes().size() + 1];
|
||||
types[0] = expression.getReturnType();
|
||||
for (int i = 0; i < expression.getParameterTypes().size(); ++i) {
|
||||
types[i + 1] = expression.getParameterTypes().get(i);
|
||||
}
|
||||
|
||||
consumer.accept(new WasmSignature(types));
|
||||
}
|
||||
}
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.render;
|
||||
|
||||
import org.teavm.backend.wasm.generate.WasmGenerationContext;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||
|
@ -45,6 +43,7 @@ import org.teavm.backend.wasm.model.expression.WasmLoadFloat64;
|
|||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt64;
|
||||
import org.teavm.backend.wasm.model.expression.WasmMemoryGrow;
|
||||
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStoreFloat32;
|
||||
|
@ -57,13 +56,8 @@ import org.teavm.backend.wasm.model.expression.WasmTry;
|
|||
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
|
||||
|
||||
public class WasmTypeInference implements WasmExpressionVisitor {
|
||||
private WasmGenerationContext context;
|
||||
private WasmType result;
|
||||
|
||||
public WasmTypeInference(WasmGenerationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public WasmType getResult() {
|
||||
return result;
|
||||
}
|
||||
|
@ -155,18 +149,23 @@ public class WasmTypeInference implements WasmExpressionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(WasmConversion expression) {
|
||||
result = expression.getTargetType();
|
||||
result = WasmType.num(expression.getTargetType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmNullConstant expression) {
|
||||
result = expression.type.getReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmCall expression) {
|
||||
WasmFunction function = context.getFunction(expression.getFunctionName());
|
||||
result = function == null ? null : function.getResult();
|
||||
var function = expression.getFunction();
|
||||
result = function == null ? null : function.getType().getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WasmIndirectCall expression) {
|
||||
result = expression.getReturnType();
|
||||
result = expression.getType().getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.transformation;
|
||||
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
@ -25,33 +26,32 @@ import org.teavm.backend.wasm.model.expression.WasmReplacingExpressionVisitor;
|
|||
|
||||
public class IndirectCallTraceTransformation {
|
||||
private WasmModule module;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
|
||||
public IndirectCallTraceTransformation(WasmModule module) {
|
||||
public IndirectCallTraceTransformation(WasmModule module, WasmFunctionTypes functionTypes) {
|
||||
this.module = module;
|
||||
this.functionTypes = functionTypes;
|
||||
}
|
||||
|
||||
public void apply() {
|
||||
WasmFunction traceFunction = new WasmFunction("traceIndirectCall");
|
||||
var traceFunction = new WasmFunction(functionTypes.of(WasmType.INT32, WasmType.INT32, WasmType.INT32));
|
||||
traceFunction.setName("traceIndirectCall");
|
||||
traceFunction.setImportModule("debug");
|
||||
traceFunction.setImportName("traceIndirectCall");
|
||||
traceFunction.getParameters().add(WasmType.INT32);
|
||||
traceFunction.getParameters().add(WasmType.INT32);
|
||||
traceFunction.setResult(WasmType.INT32);
|
||||
module.add(traceFunction);
|
||||
module.functions.add(traceFunction);
|
||||
|
||||
int[] positionHolder = { 0 };
|
||||
WasmReplacingExpressionVisitor visitor = new WasmReplacingExpressionVisitor(expression -> {
|
||||
var visitor = new WasmReplacingExpressionVisitor(expression -> {
|
||||
if (expression instanceof WasmIndirectCall) {
|
||||
WasmIndirectCall indirectCall = (WasmIndirectCall) expression;
|
||||
WasmCall call = new WasmCall(traceFunction.getName());
|
||||
call.setImported(true);
|
||||
var indirectCall = (WasmIndirectCall) expression;
|
||||
var call = new WasmCall(traceFunction);
|
||||
call.getArguments().add(new WasmInt32Constant(positionHolder[0]++));
|
||||
call.getArguments().add(indirectCall.getSelector());
|
||||
indirectCall.setSelector(call);
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (var function : module.functions) {
|
||||
visitor.replace(function);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.transformation;
|
||||
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
|
@ -25,33 +26,32 @@ import org.teavm.backend.wasm.model.expression.WasmReplacingExpressionVisitor;
|
|||
|
||||
public class MemoryAccessTraceTransformation {
|
||||
private WasmModule module;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
|
||||
public MemoryAccessTraceTransformation(WasmModule module) {
|
||||
public MemoryAccessTraceTransformation(WasmModule module, WasmFunctionTypes functionTypes) {
|
||||
this.module = module;
|
||||
this.functionTypes = functionTypes;
|
||||
}
|
||||
|
||||
public void apply() {
|
||||
WasmFunction traceFunction = new WasmFunction("traceMemoryAccess");
|
||||
var traceFunction = new WasmFunction(functionTypes.of(WasmType.INT32, WasmType.INT32, WasmType.INT32));
|
||||
traceFunction.setImportModule("debug");
|
||||
traceFunction.setName("traceMemoryAccess");
|
||||
traceFunction.setImportName("traceMemoryAccess");
|
||||
traceFunction.getParameters().add(WasmType.INT32);
|
||||
traceFunction.getParameters().add(WasmType.INT32);
|
||||
traceFunction.setResult(WasmType.INT32);
|
||||
module.add(traceFunction);
|
||||
module.functions.add(traceFunction);
|
||||
|
||||
int[] positionHolder = { 0 };
|
||||
WasmReplacingExpressionVisitor visitor = new WasmReplacingExpressionVisitor(expression -> {
|
||||
var visitor = new WasmReplacingExpressionVisitor(expression -> {
|
||||
if (expression instanceof WasmMemoryAccess) {
|
||||
WasmMemoryAccess memoryAccess = (WasmMemoryAccess) expression;
|
||||
WasmCall call = new WasmCall(traceFunction.getName());
|
||||
call.setImported(true);
|
||||
WasmCall call = new WasmCall(traceFunction);
|
||||
call.getArguments().add(new WasmInt32Constant(positionHolder[0]++));
|
||||
call.getArguments().add(memoryAccess.getIndex());
|
||||
memoryAccess.setIndex(call);
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
for (WasmFunction function : module.getFunctions().values()) {
|
||||
for (var function : module.functions) {
|
||||
visitor.replace(function);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,14 +132,14 @@ public class ResourceReadIntrinsic implements WasmIntrinsic {
|
|||
switch (invocation.getMethod().getName()) {
|
||||
case "keys": {
|
||||
WasmExpression map = manager.generate(invocation.getArguments().get(0));
|
||||
WasmCall call = new WasmCall(manager.getNames().forMethod(KEYS_METHOD));
|
||||
var call = new WasmCall(manager.getFunctions().forStaticMethod(KEYS_METHOD));
|
||||
call.getArguments().add(map);
|
||||
return call;
|
||||
}
|
||||
case "has": {
|
||||
WasmExpression map = manager.generate(invocation.getArguments().get(0));
|
||||
WasmExpression key = manager.generate(invocation.getArguments().get(1));
|
||||
WasmCall call = new WasmCall(manager.getNames().forMethod(LOOKUP_METHOD));
|
||||
WasmCall call = new WasmCall(manager.getFunctions().forStaticMethod(LOOKUP_METHOD));
|
||||
call.getArguments().add(map);
|
||||
call.getArguments().add(key);
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.NE, call,
|
||||
|
@ -151,7 +151,7 @@ public class ResourceReadIntrinsic implements WasmIntrinsic {
|
|||
|
||||
WasmExpression map = manager.generate(invocation.getArguments().get(0));
|
||||
WasmExpression key = manager.generate(invocation.getArguments().get(1));
|
||||
WasmCall call = new WasmCall(manager.getNames().forMethod(LOOKUP_METHOD));
|
||||
WasmCall call = new WasmCall(manager.getFunctions().forStaticMethod(LOOKUP_METHOD));
|
||||
call.getArguments().add(map);
|
||||
call.getArguments().add(key);
|
||||
WasmLocal entryVar = manager.getTemporary(WasmType.INT32);
|
||||
|
|
Loading…
Reference in New Issue
Block a user