From bb0029571483cdb4359359c7f978fed62976c891 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sun, 25 Jun 2023 12:10:39 +0100 Subject: Write symbol infos for functions --- .../wasm/structure/ast/modules/WasmModule.java | 45 ++++++- .../structure/binary/WasmBinaryFormatLinking.java | 150 +++++++++++++++++++++ .../structure/binary/WasmBinaryFormatModules.java | 2 + .../binary/WasmBinaryFormatNameSection.java | 18 +-- 4 files changed, 196 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatLinking.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/modules/WasmModule.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/modules/WasmModule.java index 6772e6ae..7395d996 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/modules/WasmModule.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/modules/WasmModule.java @@ -25,18 +25,53 @@ public record WasmModule( P.vector() ); - public record IndexedFunction(WasmFuncIndex funcIndex, WasmFunction function) { + public sealed interface IndexedFunction { + record Import(WasmFuncIndex funcIndex, WasmImportDescriptor.Func descriptor) implements IndexedFunction { + @Override + public String name() { + return descriptor.identifier(); + } + } + + record Definition(WasmFuncIndex funcIndex, WasmFunction function) implements IndexedFunction { + @Override + public String name() { + return function.name(); + } + } + + WasmFuncIndex funcIndex(); + String name(); } public List indexedFunctions() { - var funcIndex = imports.stream() + var indexedFunctions = new ArrayList(); + + for (var import_ : imports) { + if (import_.descriptor() instanceof WasmImportDescriptor.Func func) { + var funcIndex = new WasmFuncIndex(indexedFunctions.size()); + indexedFunctions.add(new IndexedFunction.Import(funcIndex, func)); + } + } + + for (var function : functions) { + var funcIndex = new WasmFuncIndex(indexedFunctions.size()); + indexedFunctions.add(new IndexedFunction.Definition(funcIndex, function)); + } + + return indexedFunctions; + } + + public List indexedFunctionDefinitions() { + var startIndex = imports.stream() .filter(import_ -> import_.descriptor() instanceof WasmImportDescriptor.Func) .count(); - var indexedFunctions = new ArrayList(); + var indexedFunctions = new ArrayList(); + for (var function : functions) { - indexedFunctions.add(new IndexedFunction(new WasmFuncIndex((int) funcIndex), function)); - funcIndex++; + var funcIndex = new WasmFuncIndex((int) startIndex + indexedFunctions.size()); + indexedFunctions.add(new IndexedFunction.Definition(funcIndex, function)); } return indexedFunctions; diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatLinking.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatLinking.java new file mode 100644 index 00000000..59bab46e --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatLinking.java @@ -0,0 +1,150 @@ +package org.shedlang.compiler.backends.wasm.structure.binary; + +import org.shedlang.compiler.backends.wasm.structure.BinaryWriter; +import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmFuncIndex; +import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmModule; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatConventions.writeVec; +import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatModules.writeCustomSection; +import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatModules.writeFuncIndex; +import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatSize.writeSize; +import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatValues.writeString; + +public class WasmBinaryFormatLinking { + // Corresponds to https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md + + private WasmBinaryFormatLinking() { + } + + // == Linking Metadata Section == + + private static final int VERSION = 2; + + public static void writeLinkingSection( + WasmModule module, + WasmIndexTable indexTable, + BinaryWriter writer + ) throws IOException { + writeCustomSection("linking", writer, () -> { + Leb128Encoding.encodeUnsignedInt32(VERSION, writer); + writeSymbolTableSubsection(module, indexTable, writer); + }); + } + + private static void writeSubsection( + SubsectionType type, + BinaryWriter writer, + WasmBinaryFormatModules.Write writeContent + ) throws IOException { + writer.writeByte(type.id); + writeSize(writer, writeContent::write); + } + + private enum SubsectionType { + WASM_SEGMENT_INFO(5), + WASM_INIT_FUNCS(6), + WASM_COMDAT_INFO(7), + WASM_SYMBOL_TABLE(8); + + private final byte id; + + SubsectionType(int id) { + this.id = (byte) id; + } + } + + private static void writeSymbolTableSubsection( + WasmModule module, + WasmIndexTable indexTable, + BinaryWriter writer + ) throws IOException { + writeSubsection(SubsectionType.WASM_SYMBOL_TABLE, writer, () -> { + writeVec( + symbolInfos(module), + symbolInfo -> writeSymbolInfo(symbolInfo, writer), + writer + ); + }); + } + + private static void writeSymbolInfo(SymbolInfo symbolInfo, BinaryWriter writer) { + switch (symbolInfo) { + case SymbolInfo.Function function -> { + writer.writeByte(SymbolType.FUNCTION.id); + Leb128Encoding.encodeUnsignedInt32(flagsToInt(function.flags), writer); + writeFuncIndex(function.funcIndex, writer); + writeString(function.name(), writer); + } + } + } + + private enum SymbolType { + FUNCTION(0), + DATA(1), + GLOBAL(2), + SECTION(3), + EVENT(4), + TABLE(5); + + private final byte id; + + SymbolType(int id) { + this.id = (byte) id; + } + } + + private static List symbolInfos(WasmModule module) { + return module.indexedFunctions().stream() + .map(function -> { + var flags = switch (function) { + case WasmModule.IndexedFunction.Definition definition -> + List.of(); + + case WasmModule.IndexedFunction.Import import_ -> + List.of(SymbolFlag.UNDEFINED, SymbolFlag.EXPLICIT_NAME); + }; + return new SymbolInfo.Function( + flags, + function.funcIndex(), + function.name() + ); + }) + .toList(); + } + + private sealed interface SymbolInfo { + record Function(List flags, WasmFuncIndex funcIndex, String name) implements SymbolInfo { + + } + } + + private enum SymbolFlag { + BINDING_WEAK(0x01), + BINDING_LOCAL(0x02), + BINDING_VISIBILITY_HIDDEN(0x04), + UNDEFINED(0x10), + EXPORTED(0x20), + EXPLICIT_NAME(0x40), + NO_STRIP(0x80); + + private final int value; + + SymbolFlag(int value) { + this.value = value; + } + } + + private static int flagsToInt(Collection flags) { + var asInt = 0; + + for (var flag : flags) { + asInt |= flag.value; + } + + return asInt; + } +} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatModules.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatModules.java index 41a84e2a..ef1c6afb 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatModules.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatModules.java @@ -14,6 +14,7 @@ import java.util.List; import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatConventions.writeVec; import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatInstructions.writeExpression; +import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatLinking.writeLinkingSection; import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatNameSection.writeNameSection; import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatSize.writeSize; import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatTypes.*; @@ -305,6 +306,7 @@ public class WasmBinaryFormatModules { writeElementSection(module, writer); writeCodeSection(module, writer); writeNameSection(module, indexTable, writer); + writeLinkingSection(module, indexTable, writer); outputStream.write(writer.toBytes()); } diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatNameSection.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatNameSection.java index e5142955..4c4f948a 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatNameSection.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatNameSection.java @@ -2,12 +2,10 @@ package org.shedlang.compiler.backends.wasm.structure.binary; import org.shedlang.compiler.backends.wasm.structure.BinaryWriter; import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmFuncIndex; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmImportDescriptor; import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmLocal; import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmModule; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; @@ -81,17 +79,9 @@ public class WasmBinaryFormatNameSection { private static void writeFunctionNameSubsection(WasmModule module, BinaryWriter writer) throws IOException { writeNameSubsection(NameSubsectionId.FUNCTION_NAMES, writer, () -> { - var functionNames = new ArrayList(); - for (var import_ : module.imports()) { - if (import_.descriptor() instanceof WasmImportDescriptor.Func func) { - var funcIndex = new WasmFuncIndex(functionNames.size()); - functionNames.add(new NameAssoc(funcIndex, func.identifier())); - } - } - for (var function : module.functions()) { - var fundIndex = new WasmFuncIndex(functionNames.size()); - functionNames.add(new NameAssoc(fundIndex, function.name())); - } + var functionNames = module.indexedFunctions().stream() + .map(function -> new NameAssoc(function.funcIndex(), function.name())) + .toList(); writeNameMap(writer, functionNames); }); @@ -106,7 +96,7 @@ public class WasmBinaryFormatNameSection { ) throws IOException { writeNameSubsection(NameSubsectionId.LOCAL_NAMES, writer, () -> { writeVec( - module.indexedFunctions(), + module.indexedFunctionDefinitions(), indexedFunction -> { writeFuncIndex(indexedFunction.funcIndex(), writer); -- cgit v1.2.3