From a5212fb9caf95405d2cea3fc18b8b97e37ef3c29 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 4 Oct 2024 09:40:54 +0200 Subject: [PATCH] wasm gc: support imported functions in disassembler --- .../backend/wasm/disasm/Disassembler.java | 19 ++--- .../DisassemblyImportSectionListener.java | 84 +++++++++++++++++++ .../wasm/disasm/DisassemblyWriter.java | 2 + .../wasm/render/WasmBinaryRenderer.java | 2 +- 4 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyImportSectionListener.java diff --git a/core/src/main/java/org/teavm/backend/wasm/disasm/Disassembler.java b/core/src/main/java/org/teavm/backend/wasm/disasm/Disassembler.java index 5131f5abf..90024f351 100644 --- a/core/src/main/java/org/teavm/backend/wasm/disasm/Disassembler.java +++ b/core/src/main/java/org/teavm/backend/wasm/disasm/Disassembler.java @@ -27,7 +27,6 @@ import org.teavm.backend.wasm.parser.CodeSectionParser; import org.teavm.backend.wasm.parser.FunctionSectionListener; import org.teavm.backend.wasm.parser.FunctionSectionParser; import org.teavm.backend.wasm.parser.GlobalSectionParser; -import org.teavm.backend.wasm.parser.ImportSectionListener; import org.teavm.backend.wasm.parser.ImportSectionParser; import org.teavm.backend.wasm.parser.ModuleParser; import org.teavm.backend.wasm.parser.NameSectionListener; @@ -41,6 +40,7 @@ public final class Disassembler { private DisassemblyWriter writer; private WasmHollowFunctionType[] functionTypes; private int[] functionTypeRefs; + private int importFunctionCount; public Disassembler(DisassemblyWriter writer) { this.writer = writer; @@ -91,17 +91,6 @@ public final class Disassembler { }; } - ImportListenerImpl importListener = new ImportListenerImpl(); - - static class ImportListenerImpl implements ImportSectionListener { - int count; - - @Override - public void function(int typeIndex) { - ++count; - } - } - public Consumer getSectionConsumer(int code, int pos, NameProvider nameProvider) { if (code == 1) { return bytes -> { @@ -115,13 +104,15 @@ public final class Disassembler { }; } else if (code == 2) { return bytes -> { + var importListener = new DisassemblyImportSectionListener(writer, nameProvider, functionTypes); var parser = new ImportSectionParser(importListener); parser.parse(AddressListener.EMPTY, bytes); + importFunctionCount = importListener.functionCount(); }; } else if (code == 3) { return bytes -> { var signatures = new IntArrayList(); - for (var i = 0; i < importListener.count; ++i) { + for (var i = 0; i < importFunctionCount; ++i) { signatures.add(0); } var parser = new FunctionSectionParser(new FunctionSectionListener() { @@ -150,7 +141,7 @@ public final class Disassembler { writer.setAddressOffset(pos); writer.write("(; code section size: " + bytes.length + " ;)").eol(); var sectionParser = new CodeSectionParser(disassembler); - sectionParser.setFunctionIndexOffset(importListener.count); + sectionParser.setFunctionIndexOffset(importFunctionCount); sectionParser.parse(writer.addressListener, bytes); writer.flush(); }; diff --git a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyImportSectionListener.java b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyImportSectionListener.java new file mode 100644 index 000000000..068eab298 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyImportSectionListener.java @@ -0,0 +1,84 @@ +/* + * 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.disasm; + +import org.teavm.backend.wasm.parser.ImportSectionListener; +import org.teavm.backend.wasm.parser.WasmHollowFunctionType; + +public class DisassemblyImportSectionListener extends BaseDisassemblyListener implements ImportSectionListener { + private WasmHollowFunctionType[] functionTypes; + private String currentModule; + private String currentName; + private int functionIndex; + + public DisassemblyImportSectionListener(DisassemblyWriter writer, NameProvider nameProvider, + WasmHollowFunctionType[] functionTypes) { + super(writer, nameProvider); + this.functionTypes = functionTypes; + } + + public int functionCount() { + return functionIndex; + } + + @Override + public void startEntry(String module, String name) { + currentModule = module; + currentName = name; + } + + @Override + public void function(int typeIndex) { + writer.address().write("(import \"").write(currentModule).write("\" \"") + .write(currentName).write("\" "); + writer.write("(func "); + writer.startLinkTarget("f" + functionIndex).write("(; " + functionIndex + " ;)"); + var name = nameProvider.function(functionIndex); + if (name != null) { + writer.write(" $").write(name); + } + writer.endLinkTarget(); + + writer.write(" (type "); + writeTypeRef(typeIndex); + writer.write(")"); + writer.indent().eol(); + + var type = typeIndex < functionTypes.length ? functionTypes[typeIndex] : null; + if (type != null) { + for (var i = 0; i < type.parameterTypes.length; ++i) { + writer.write("(param "); + writer.startLinkTarget("l" + functionIndex + "." + i).write(" (; " + i + " ;)"); + var paramName = nameProvider.local(functionIndex, i); + if (paramName != null) { + writer.write(" $").write(paramName); + } + writer.endLinkTarget(); + writer.write(" "); + writeType(type.parameterTypes[i]); + writer.write(")").eol(); + } + for (var i = 0; i < type.returnTypes.length; ++i) { + writer.write("(result "); + writeType(type.returnTypes[i]); + writer.write(")").eol(); + } + } + writer.outdent().write("))").eol(); + + functionIndex++; + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyWriter.java b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyWriter.java index 5227ebdee..ed57a6e76 100644 --- a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyWriter.java +++ b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyWriter.java @@ -112,6 +112,8 @@ public abstract class DisassemblyWriter { out.flush(); } + + public final AddressListener addressListener = new AddressListener() { @Override public void address(int address) { diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java index 9104c6df8..0c827c8c7 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java @@ -462,7 +462,7 @@ public class WasmBinaryRenderer { WasmBinaryWriter functionsSubsection = new WasmBinaryWriter(); var functions = module.functions.stream() - .filter(f -> f.getName() != null && f.getImportName() == null) + .filter(f -> f.getName() != null) .collect(Collectors.toList()); functionsSubsection.writeLEB(functions.size());