aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-06-25 21:50:06 +0100
committerMichael Williamson <mike@zwobble.org>2023-06-25 21:50:06 +0100
commiteff16c83d2e3b7c22d071eee55118910b6b6941d (patch)
treedb88c315d8c37523d6a3a20695bd86bb28a52925 /src/main/java
parent26e73674db626d51f9eb57349f219907f524b178 (diff)
Support relocation of string address
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java2
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java3
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java3
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/WasmMemoryBuilder.java10
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java2
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmMemoryAddress.java14
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java19
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatLinking.java240
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatModules.java192
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatNameSection.java44
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatTypes.java36
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryWriter.java108
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmRelocationEntry.java11
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmRelocationType.java39
-rw-r--r--src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmSectionId.java28
15 files changed, 500 insertions, 251 deletions
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java
index d65d25b5..8e8c2735 100644
--- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java
@@ -42,7 +42,7 @@ public class WasmCodeGen {
var offset = defineStringResult.value();
context = defineStringResult.context();
- yield context.addInstruction(new WasmI32Const(offset));
+ yield context.addInstruction(offset);
}
case PushUnitInstruction pushUnit ->
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java
index 10f55c68..46756088 100644
--- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java
@@ -5,6 +5,7 @@ import org.pcollections.OrderedPMap;
import org.pcollections.PMap;
import org.pcollections.PVector;
import org.shedlang.compiler.backends.llvm.NameAllocator;
+import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmMemoryAddress;
import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmExpression;
import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmInstruction;
import org.shedlang.compiler.backends.wasm.structure.ast.modules.*;
@@ -27,7 +28,7 @@ public record WasmCodeGenContext(
Empty.map()
);
- public WasmCodeGenResult<Integer> addData(
+ public WasmCodeGenResult<WasmMemoryAddress> addData(
WasmCodeGenGlobalSpace space,
byte[] data,
WasmAlignment alignment
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java
index a2431e60..acf29b4d 100644
--- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java
@@ -1,5 +1,6 @@
package org.shedlang.compiler.backends.wasm;
+import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmMemoryAddress;
import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmAlignment;
import java.nio.ByteBuffer;
@@ -9,7 +10,7 @@ public class WasmCodeGenStrings {
private WasmCodeGenStrings() {
}
- public static WasmCodeGenResult<Integer> defineString(
+ public static WasmCodeGenResult<WasmMemoryAddress> defineString(
String value,
WasmCodeGenContext context
) {
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmMemoryBuilder.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmMemoryBuilder.java
index 579fc586..d3dc728c 100644
--- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmMemoryBuilder.java
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmMemoryBuilder.java
@@ -2,6 +2,7 @@ package org.shedlang.compiler.backends.wasm;
import org.pcollections.OrderedPMap;
import org.shedlang.compiler.backends.llvm.NameAllocator;
+import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmMemoryAddress;
import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmExpression;
import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmI32Const;
import org.shedlang.compiler.backends.wasm.structure.ast.linking.WasmDataSegmentIndex;
@@ -20,6 +21,8 @@ import java.util.Optional;
public class WasmMemoryBuilder {
public static final WasmMemoryBuilder EMPTY = new WasmMemoryBuilder(OrderedPMap.empty(), 0);
+ private static final WasmDataSegmentIndex DATA_SEGMENT_INDEX = new WasmDataSegmentIndex(0);
+
private final OrderedPMap<String, Entity> entities;
private final int size;
@@ -48,7 +51,7 @@ public class WasmMemoryBuilder {
entities.values().stream()
.map(entity -> new WasmDataSymbol(
entity.name,
- new WasmDataSegmentIndex(0),
+ DATA_SEGMENT_INDEX,
entity.offset,
entity.data.length
))
@@ -59,7 +62,7 @@ public class WasmMemoryBuilder {
return module;
}
- public record Result(int offset, WasmMemoryBuilder memory) {
+ public record Result(WasmMemoryAddress offset, WasmMemoryBuilder memory) {
}
public Result add(
@@ -82,8 +85,7 @@ public class WasmMemoryBuilder {
entities.plus(fullName, new Entity(fullName, offset, data, alignment)),
offset + data.length
);
- // TODO: return relocated offset
- return new Result(offset, builder);
+ return new Result(new WasmMemoryAddress(DATA_SEGMENT_INDEX, offset), builder);
}
private record Entity(String name, int offset, byte[] data, WasmAlignment alignment) {
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java
index 9467a9e7..4e1cc958 100644
--- a/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java
@@ -1,4 +1,4 @@
package org.shedlang.compiler.backends.wasm.structure.ast.instructions;
-public sealed interface WasmInstruction permits WasmDrop, WasmI32Const, WasmI64Const, WasmLocalGet, WasmLocalSet, WasmReturn {
+public sealed interface WasmInstruction permits WasmDrop, WasmI32Const, WasmI64Const, WasmLocalGet, WasmLocalSet, WasmMemoryAddress, WasmReturn {
}
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmMemoryAddress.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmMemoryAddress.java
new file mode 100644
index 00000000..704f7f16
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmMemoryAddress.java
@@ -0,0 +1,14 @@
+package org.shedlang.compiler.backends.wasm.structure.ast.instructions;
+
+import org.shedlang.compiler.backends.wasm.structure.ast.linking.WasmDataSegmentIndex;
+
+/**
+ * This is a fake instruction that corresponds to an i32.const instruction for
+ * an offset into a data segment. Encapsulating this in its own instruction
+ * avoids having to separately track relocation.
+ */
+public record WasmMemoryAddress(
+ WasmDataSegmentIndex dataSegmentIndex,
+ int dataSegmentOffset
+) implements WasmInstruction {
+}
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java
index 09161143..f58c396a 100644
--- a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java
@@ -1,6 +1,5 @@
package org.shedlang.compiler.backends.wasm.structure.binary;
-import org.shedlang.compiler.backends.wasm.structure.BinaryWriter;
import org.shedlang.compiler.backends.wasm.structure.ast.instructions.*;
import java.io.IOException;
@@ -13,7 +12,10 @@ public class WasmBinaryFormatInstructions {
private WasmBinaryFormatInstructions() {
}
- private static void writeInstruction(WasmInstruction instruction, BinaryWriter writer) {
+ private static void writeInstruction(
+ WasmInstruction instruction,
+ WasmBinaryWriter writer
+ ) {
switch (instruction) {
// == Control Instructions ==
@@ -44,11 +46,18 @@ public class WasmBinaryFormatInstructions {
case WasmI32Const i32Const -> {
writer.writeByte(0x41);
- Leb128Encoding.encodeSignedInt32(i32Const.value(), writer);
+ writer.writeSignedInt32(i32Const.value());
}
case WasmI64Const i64Const -> {
writer.writeByte(0x42);
- Leb128Encoding.encodeSignedInt64(i64Const.value(), writer);
+ writer.writeSignedInt64(i64Const.value());
+ }
+
+ // == Relocatable Instructions ==
+
+ case WasmMemoryAddress memoryAddress -> {
+ writer.writeByte(0x41);
+ writer.writeRelocatableUnsignedInt32(WasmRelocationType.MEMORY_ADDR_SLEB, memoryAddress);
}
}
}
@@ -57,7 +66,7 @@ public class WasmBinaryFormatInstructions {
static void writeExpression(
WasmExpression expression,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
for (var instruction : expression.instructions()) {
writeInstruction(instruction, writer);
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
index ecc06f71..224508ec 100644
--- 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
@@ -1,6 +1,6 @@
package org.shedlang.compiler.backends.wasm.structure.binary;
-import org.shedlang.compiler.backends.wasm.structure.BinaryWriter;
+import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmMemoryAddress;
import org.shedlang.compiler.backends.wasm.structure.ast.linking.WasmDataSegmentIndex;
import org.shedlang.compiler.backends.wasm.structure.ast.linking.WasmDataSymbol;
import org.shedlang.compiler.backends.wasm.structure.ast.linking.WasmInitFunc;
@@ -11,14 +11,9 @@ import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmGlobalIndex
import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmModule;
import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Stream;
+import java.util.*;
-import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatConventions.writeVec;
import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatModules.*;
-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
@@ -26,19 +21,74 @@ public class WasmBinaryFormatLinking {
private WasmBinaryFormatLinking() {
}
+ public static void writeLinkingSections(
+ WasmModule module,
+ WasmBinaryWriter writer
+ ) throws IOException {
+ var symbolTable = generateSymbolTable(module);
+
+ writeLinkingSection(module, symbolTable, writer);
+ writeRelocationSections(symbolTable, writer);
+ }
+
+ // == Relocation Sections ==
+
+ private static void writeRelocationSections(
+ SymbolTable symbolTable,
+ WasmBinaryWriter writer
+ ) throws IOException {
+ for (var relocationEntriesForSection : writer.relocationEntries().entrySet()) {
+ writeRelocationSection(
+ relocationEntriesForSection.getKey(),
+ relocationEntriesForSection.getValue(),
+ symbolTable,
+ writer
+ );
+ }
+ }
+
+ private static void writeRelocationSection(
+ int sectionIndex,
+ List<WasmRelocationEntry> relocationEntries,
+ SymbolTable symbolTable,
+ WasmBinaryWriter writer
+ ) throws IOException {
+ // TODO: don't assume CODE
+ writeCustomSection("reloc.CODE", writer, () -> {
+ writer.writeUnsignedInt32(sectionIndex);
+ writer.writeVec(
+ relocationEntries,
+ relocationEntry -> writeRelocationEntry(relocationEntry, symbolTable, writer)
+ );
+ });
+ }
+
+ private static void writeRelocationEntry(
+ WasmRelocationEntry relocationEntry,
+ SymbolTable symbolTable,
+ WasmBinaryWriter writer
+ ) {
+ var symbolIndex = symbolTable.memoryAddressToSymbolIndex(relocationEntry.index());
+
+ writer.writeByte(relocationEntry.type().id());
+ writer.writeUnsignedInt32(relocationEntry.sectionContentsOffset());
+ writer.writeUnsignedInt32(symbolIndex.value());
+
+ // TODO: handle types without addends
+ writer.writeSignedInt32(0);
+ }
+
// == Linking Metadata Section ==
- private static final int VERSION = 2;
+ private static final int LINKING_SECTION_VERSION = 2;
- public static void writeLinkingSection(
+ private static void writeLinkingSection(
WasmModule module,
- WasmIndexTable indexTable,
- BinaryWriter writer
+ SymbolTable symbolTable,
+ WasmBinaryWriter writer
) throws IOException {
writeCustomSection("linking", writer, () -> {
- Leb128Encoding.encodeUnsignedInt32(VERSION, writer);
-
- var symbolTable = generateSymbolTable(module);
+ writer.writeUnsignedInt32(LINKING_SECTION_VERSION);
writeSegmentInfoSubsection(module, writer);
writeSymbolTableSubsection(symbolTable, writer);
@@ -48,11 +98,11 @@ public class WasmBinaryFormatLinking {
private static void writeSubsection(
SubsectionType type,
- BinaryWriter writer,
+ WasmBinaryWriter writer,
WasmBinaryFormatModules.Write writeContent
) throws IOException {
writer.writeByte(type.id);
- writeSize(writer, writeContent::write);
+ writer.writeSize(writeContent::write);
}
private enum SubsectionType {
@@ -70,18 +120,17 @@ public class WasmBinaryFormatLinking {
private static void writeSegmentInfoSubsection(
WasmModule module,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (module.dataSegments().size() > 0) {
writeSubsection(SubsectionType.WASM_SEGMENT_INFO, writer, () -> {
- writeVec(
+ writer.writeVec(
module.dataSegments(),
dataSegment -> {
- writeString(dataSegment.name(), writer);
+ writer.writeString(dataSegment.name());
writeAlignment(dataSegment.alignment(), writer);
writeFlags(List.of(), writer);
- },
- writer
+ }
);
});
}
@@ -90,16 +139,15 @@ public class WasmBinaryFormatLinking {
private static void writeInitFuncsSubsection(
WasmModule module,
SymbolTable symbolTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (module.initFuncs().size() > 0) {
writeSubsection(SubsectionType.WASM_INIT_FUNCS, writer, () -> {
- writeVec(
+ writer.writeVec(
module.initFuncs(),
initFunc -> {
writeInitFunc(initFunc, symbolTable, writer);
- },
- writer
+ }
);
});
}
@@ -108,49 +156,48 @@ public class WasmBinaryFormatLinking {
private static void writeInitFunc(
WasmInitFunc initFunc,
SymbolTable symbolTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) {
- Leb128Encoding.encodeUnsignedInt32(initFunc.priority(), writer);
+ writer.writeUnsignedInt32(initFunc.priority());
var symbolIndex = symbolTable.funcIndexToSymbolIndex(initFunc.funcIndex());
writeSymbolIndex(symbolIndex, writer);
}
private static void writeSymbolTableSubsection(
SymbolTable symbolTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (symbolTable.symbolInfos.size() > 0) {
writeSubsection(SubsectionType.WASM_SYMBOL_TABLE, writer, () -> {
- writeVec(
+ writer.writeVec(
symbolTable.symbolInfos,
- symbolInfo -> writeSymbolInfo(symbolInfo, writer),
- writer
+ symbolInfo -> writeSymbolInfo(symbolInfo, writer)
);
});
}
}
- private static void writeSymbolInfo(SymbolInfo symbolInfo, BinaryWriter writer) {
+ private static void writeSymbolInfo(SymbolInfo symbolInfo, WasmBinaryWriter writer) {
switch (symbolInfo) {
case SymbolInfo.Function function -> {
writer.writeByte(SymbolType.FUNCTION.id);
writeFlags(function.flags, writer);
writeFuncIndex(function.funcIndex, writer);
- writeString(function.name(), writer);
+ writer.writeString(function.name());
}
case SymbolInfo.Data data -> {
writer.writeByte(SymbolType.DATA.id);
writeFlags(data.flags, writer);
- writeString(data.dataSymbol.name(), writer);
+ writer.writeString(data.dataSymbol.name());
writeDataSegmentIndex(data.dataSymbol.dataSegmentIndex(), writer);
- Leb128Encoding.encodeUnsignedInt32(data.dataSymbol.offset(), writer);
- Leb128Encoding.encodeUnsignedInt32(data.dataSymbol.size(), writer);
+ writer.writeUnsignedInt32(data.dataSymbol.offset());
+ writer.writeUnsignedInt32(data.dataSymbol.size());
}
case SymbolInfo.Global global -> {
writer.writeByte(SymbolType.GLOBAL.id);
writeFlags(global.flags, writer);
writeGlobalIndex(global.globalIndex, writer);
- writeString(global.name(), writer);
+ writer.writeString(global.name());
}
}
}
@@ -173,62 +220,87 @@ public class WasmBinaryFormatLinking {
private static class SymbolTable {
private final List<SymbolInfo> symbolInfos;
private final int functionSymbolIndexOffset;
+ private final Map<WasmMemoryAddress, WasmSymbolIndex> memoryAddressToSymbolIndex;
- public SymbolTable(List<SymbolInfo> symbolInfos, int functionSymbolIndexOffset) {
+ public SymbolTable(
+ List<SymbolInfo> symbolInfos,
+ int functionSymbolIndexOffset,
+ Map<WasmMemoryAddress, WasmSymbolIndex> memoryAddressToSymbolIndex
+ ) {
this.symbolInfos = symbolInfos;
this.functionSymbolIndexOffset = functionSymbolIndexOffset;
+ this.memoryAddressToSymbolIndex = memoryAddressToSymbolIndex;
}
public WasmSymbolIndex funcIndexToSymbolIndex(WasmFuncIndex funcIndex) {
return new WasmSymbolIndex(funcIndex.value() + functionSymbolIndexOffset);
}
+
+ public WasmSymbolIndex memoryAddressToSymbolIndex(WasmMemoryAddress memoryAddress) {
+ var symbolIndex = memoryAddressToSymbolIndex.get(memoryAddress);
+ if (symbolIndex == null) {
+ // TODO: better error
+ throw new RuntimeException("could not find symbol index for " + memoryAddress);
+ } else {
+ return symbolIndex;
+ }
+
+ }
}
private static SymbolTable generateSymbolTable(WasmModule module) {
- var functionSymbolIndexOffset = 0;
- var functionSymbols = module.indexedFunctions().stream()
- .map(function -> {
- var flags = switch (function) {
- case WasmModule.IndexedFunction.Definition definition ->
- List.<SymbolFlag>of();
-
- case WasmModule.IndexedFunction.Import import_ ->
- List.of(SymbolFlag.UNDEFINED, SymbolFlag.EXPLICIT_NAME);
- };
- return new SymbolInfo.Function(
- flags,
- function.funcIndex(),
- function.name()
- );
- });
+ var symbolInfos = new ArrayList<SymbolInfo>();
+ var memoryAddressToSymbolIndex = new HashMap<WasmMemoryAddress, WasmSymbolIndex>();
- var dataSymbols = module.dataSegments().stream()
- .flatMap(dataSegment ->
- dataSegment.symbols().stream()
- .map(dataSymbol -> new SymbolInfo.Data(List.of(), dataSymbol))
+ var functionSymbolIndexOffset = 0;
+ for (var function : module.indexedFunctions()) {
+ var flags = switch (function) {
+ case WasmModule.IndexedFunction.Definition definition ->
+ List.<SymbolFlag>of();
+
+ case WasmModule.IndexedFunction.Import import_ ->
+ List.of(SymbolFlag.UNDEFINED, SymbolFlag.EXPLICIT_NAME);
+ };
+ var symbolInfo = new SymbolInfo.Function(
+ flags,
+ function.funcIndex(),
+ function.name()
);
+ symbolInfos.add(symbolInfo);
+ }
- var globalSymbols = module.indexedGlobals().stream()
- .map(global -> {
- var flags = switch (global) {
- case WasmModule.IndexedGlobal.Definition definition ->
- List.<SymbolFlag>of();
-
- case WasmModule.IndexedGlobal.Import import_ ->
- List.of(SymbolFlag.UNDEFINED, SymbolFlag.EXPLICIT_NAME);
- };
- return new SymbolInfo.Global(
- flags,
- global.globalIndex(),
- global.name()
+ for (var dataSegment : module.dataSegments()) {
+ for (var dataSymbol : dataSegment.symbols()) {
+ var symbolInfo = new SymbolInfo.Data(List.of(), dataSymbol);
+ memoryAddressToSymbolIndex.put(
+ new WasmMemoryAddress(dataSymbol.dataSegmentIndex(), dataSymbol.offset()),
+ new WasmSymbolIndex(symbolInfos.size())
);
- });
+ symbolInfos.add(symbolInfo);
+ }
+ }
- var symbolInfos = Stream.<Stream<? extends SymbolInfo>>of(functionSymbols, dataSymbols, globalSymbols)
- .<SymbolInfo>flatMap(x -> x)
- .toList();
+ for (var global : module.indexedGlobals()) {
+ var flags = switch (global) {
+ case WasmModule.IndexedGlobal.Definition definition ->
+ List.<SymbolFlag>of();
+
+ case WasmModule.IndexedGlobal.Import import_ ->
+ List.of(SymbolFlag.UNDEFINED, SymbolFlag.EXPLICIT_NAME);
+ };
+ var symbolInfo = new SymbolInfo.Global(
+ flags,
+ global.globalIndex(),
+ global.name()
+ );
+ symbolInfos.add(symbolInfo);
+ }
- return new SymbolTable(symbolInfos, functionSymbolIndexOffset);
+ return new SymbolTable(
+ symbolInfos,
+ functionSymbolIndexOffset,
+ memoryAddressToSymbolIndex
+ );
}
private sealed interface SymbolInfo {
@@ -268,19 +340,19 @@ public class WasmBinaryFormatLinking {
return asInt;
}
- private static void writeFlags(List<SymbolFlag> flags, BinaryWriter writer) {
- Leb128Encoding.encodeUnsignedInt32(flagsToInt(flags), writer);
+ private static void writeFlags(List<SymbolFlag> flags, WasmBinaryWriter writer) {
+ writer.writeUnsignedInt32(flagsToInt(flags));
}
- private static void writeDataSegmentIndex(WasmDataSegmentIndex dataSegmentIndex, BinaryWriter writer) {
- Leb128Encoding.encodeUnsignedInt32(dataSegmentIndex.value(), writer);
+ private static void writeDataSegmentIndex(WasmDataSegmentIndex dataSegmentIndex, WasmBinaryWriter writer) {
+ writer.writeUnsignedInt32(dataSegmentIndex.value());
}
- private static void writeSymbolIndex(WasmSymbolIndex symbolIndex, BinaryWriter writer) {
- Leb128Encoding.encodeUnsignedInt32(symbolIndex.value(), writer);
+ private static void writeSymbolIndex(WasmSymbolIndex symbolIndex, WasmBinaryWriter writer) {
+ writer.writeUnsignedInt32(symbolIndex.value());
}
- private static void writeAlignment(WasmAlignment alignment, BinaryWriter writer) {
- Leb128Encoding.encodeUnsignedInt32(alignment.alignment(), writer);
+ private static void writeAlignment(WasmAlignment alignment, WasmBinaryWriter writer) {
+ writer.writeUnsignedInt32(alignment.alignment());
}
}
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 f8a91ae3..b1b35c9d 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
@@ -12,13 +12,11 @@ import java.io.OutputStream;
import java.util.HexFormat;
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.WasmBinaryFormatLinking.*;
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.*;
-import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatValues.writeString;
public class WasmBinaryFormatModules {
// Corresponds to https://webassembly.github.io/spec/core/binary/modules.html
@@ -28,20 +26,20 @@ public class WasmBinaryFormatModules {
// == Indices ==
- static void writeTypeIndex(WasmTypeIndex typeIndex, BinaryWriter writer) {
- Leb128Encoding.encodeUnsignedInt32(typeIndex.value(), writer);
+ static void writeTypeIndex(WasmTypeIndex typeIndex, WasmBinaryWriter writer) {
+ writer.writeUnsignedInt32(typeIndex.value());
}
- static void writeFuncIndex(WasmFuncIndex funcIndex, BinaryWriter writer) {
- Leb128Encoding.encodeUnsignedInt32(funcIndex.value(), writer);
+ static void writeFuncIndex(WasmFuncIndex funcIndex, WasmBinaryWriter writer) {
+ writer.writeUnsignedInt32(funcIndex.value());
}
- static void writeGlobalIndex(WasmGlobalIndex globalIndex, BinaryWriter writer) {
- Leb128Encoding.encodeUnsignedInt32(globalIndex.value(), writer);
+ static void writeGlobalIndex(WasmGlobalIndex globalIndex, WasmBinaryWriter writer) {
+ writer.writeUnsignedInt32(globalIndex.value());
}
- static void writeLocalIndex(WasmLocalIndex localIndex, BinaryWriter writer) {
- Leb128Encoding.encodeUnsignedInt32(localIndex.value(), writer);
+ static void writeLocalIndex(WasmLocalIndex localIndex, WasmBinaryWriter writer) {
+ writer.writeUnsignedInt32(localIndex.value());
}
// == Sections ==
@@ -51,7 +49,7 @@ public class WasmBinaryFormatModules {
}
static void writeSection(
- SectionId sectionId,
+ WasmSectionId sectionId,
BinaryWriter writer,
Write writeContent
) throws IOException {
@@ -61,43 +59,20 @@ public class WasmBinaryFormatModules {
// * a one-byte section ID
// * the u32 size of the contents, in bytes
// * the actual contents
- writer.writeByte(sectionId.id);
+ writer.writeByte(sectionId.id());
writeSize(writer, writeContent::write);
}
- enum SectionId {
- CUSTOM(0),
- TYPE(1),
- IMPORT(2),
- FUNCTION(3),
- TABLE(4),
- MEMORY(5),
- GLOBAL(6),
- EXPORT(7),
- START(8),
- ELEMENT(9),
- CODE(10),
- DATA(11),
- DATA_COUNT(12),
- TAG(13);
-
- private final byte id;
-
- SectionId(int id) {
- this.id = (byte) id;
- }
- }
-
// == Custom Section ==
static void writeCustomSection(
String name,
- BinaryWriter writer,
+ WasmBinaryWriter writer,
Write writeContent
) throws IOException {
- writeSection(SectionId.CUSTOM, writer, () -> {
- writeString(name, writer);
+ writer.writeSection(WasmSectionId.CUSTOM, () -> {
+ writer.writeString(name);
writeContent.write();
});
}
@@ -106,14 +81,13 @@ public class WasmBinaryFormatModules {
private static void writeTypeSection(
OrderedPSet<WasmFuncType> types,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (types.size() > 0) {
- writeSection(SectionId.TYPE, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.TYPE, () -> {
+ writer.writeVec(
types,
- type -> writeFuncType(type, writer),
- writer
+ type -> writeFuncType(type, writer)
);
});
}
@@ -124,14 +98,13 @@ public class WasmBinaryFormatModules {
private static void writeImportSection(
WasmModule module,
WasmIndexTable indexTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (module.imports().size() > 0) {
- writeSection(SectionId.IMPORT, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.IMPORT, () -> {
+ writer.writeVec(
module.imports(),
- import_ -> writeImport(import_, indexTable, writer),
- writer
+ import_ -> writeImport(import_, indexTable, writer)
);
});
}
@@ -140,17 +113,17 @@ public class WasmBinaryFormatModules {
private static void writeImport(
WasmImport import_,
WasmIndexTable indexTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) {
- writeString(import_.moduleName(), writer);
- writeString(import_.entityName(), writer);
+ writer.writeString(import_.moduleName());
+ writer.writeString(import_.entityName());
writeImportDescriptor(import_.descriptor(), indexTable, writer);
}
private static void writeImportDescriptor(
WasmImportDescriptor descriptor,
WasmIndexTable indexTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) {
switch (descriptor) {
case WasmImportDescriptor.Func func -> {
@@ -178,17 +151,16 @@ public class WasmBinaryFormatModules {
private static void writeFunctionSection(
WasmModule module,
WasmIndexTable indexTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (module.functions().size() > 0) {
- writeSection(SectionId.FUNCTION, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.FUNCTION, () -> {
+ writer.writeVec(
module.functions(),
function -> writeTypeIndex(
indexTable.typeIndex(function.type()),
writer
- ),
- writer
+ )
);
});
}
@@ -198,38 +170,36 @@ public class WasmBinaryFormatModules {
private static void writeTableSection(
WasmModule module,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (module.tables().size() > 0) {
- writeSection(SectionId.TABLE, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.TABLE, () -> {
+ writer.writeVec(
module.tables(),
- table -> writeTable(table, writer),
- writer
+ table -> writeTable(table, writer)
);
});
}
}
- private static void writeTable(WasmTable table, BinaryWriter writer) {
+ private static void writeTable(WasmTable table, WasmBinaryWriter writer) {
writeTableType(table.type(), writer);
}
// == Memory Section ==
- private static void writeMemorySection(WasmModule module, BinaryWriter writer) throws IOException {
+ private static void writeMemorySection(WasmModule module, WasmBinaryWriter writer) throws IOException {
if (module.memories().size() > 0) {
- writeSection(SectionId.MEMORY, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.MEMORY, () -> {
+ writer.writeVec(
module.memories(),
- memory -> writeMemory(memory, writer),
- writer
+ memory -> writeMemory(memory, writer)
);
});
}
}
- private static void writeMemory(WasmMemory memory, BinaryWriter writer) {
+ private static void writeMemory(WasmMemory memory, WasmBinaryWriter writer) {
writeMemoryType(memory.type(), writer);
}
@@ -237,14 +207,13 @@ public class WasmBinaryFormatModules {
private static void writeGlobalSection(
WasmModule module,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (module.globals().size() > 0) {
- writeSection(SectionId.GLOBAL, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.GLOBAL, () -> {
+ writer.writeVec(
module.globals(),
- global -> writeGlobal(global, writer),
- writer
+ global -> writeGlobal(global, writer)
);
});
}
@@ -252,7 +221,7 @@ public class WasmBinaryFormatModules {
private static void writeGlobal(
WasmGlobal global,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
writeGlobalType(global.type(), writer);
writeExpression(global.init(), writer);
@@ -262,14 +231,13 @@ public class WasmBinaryFormatModules {
private static void writeElementSection(
WasmModule module,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
if (module.elementSegments().size() > 0) {
- writeSection(SectionId.ELEMENT, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.ELEMENT, () -> {
+ writer.writeVec(
module.elementSegments(),
- elementSegment -> writeElementSegment(elementSegment, writer),
- writer
+ elementSegment -> writeElementSegment(elementSegment, writer)
);
});
}
@@ -277,62 +245,70 @@ public class WasmBinaryFormatModules {
private static void writeElementSegment(
WasmElementSegment elementSegment,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
- Leb128Encoding.encodeUnsignedInt32(0x00, writer);
+ writer.writeUnsignedInt32(0x00);
writeExpression(new WasmExpression(List.of(new WasmI32Const(0))), writer);
- writeVec(
+ writer.writeVec(
elementSegment.elements(),
- element -> writeFuncIndex(element, writer),
- writer
+ element -> writeFuncIndex(element, writer)
);
}
// == Code Section ==
- private static void writeCodeSection(WasmModule module, BinaryWriter writer) throws IOException {
+ private static void writeCodeSection(
+ WasmModule module,
+ WasmBinaryWriter writer
+ ) throws IOException {
if (module.functions().size() > 0) {
- writeSection(SectionId.CODE, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.CODE, () -> {
+ writer.writeVec(
module.functions(),
- function -> writeCode(function, writer),
- writer
+ function -> writeCode(function, writer)
);
});
}
}
- private static void writeCode(WasmFunction function, BinaryWriter writer) throws IOException {
- writeSize(writer, () -> {
+ private static void writeCode(
+ WasmFunction function,
+ WasmBinaryWriter writer
+ ) throws IOException {
+ writer.writeSize(() -> {
writeFunction(function, writer);
});
}
- private static void writeFunction(WasmFunction function, BinaryWriter writer) throws IOException {
- writeVec(
+ private static void writeFunction(
+ WasmFunction function,
+ WasmBinaryWriter writer
+ ) throws IOException {
+ writer.writeVec(
function.locals(),
local -> {
- Leb128Encoding.encodeUnsignedInt32(1, writer);
+ writer.writeUnsignedInt32(1);
writeValueType(local.type(), writer);
- },
- writer
+ }
);
writeExpression(function.body(), writer);
}
// == Data Section ==
- private static void writeDataSection(WasmModule module, BinaryWriter writer) throws IOException {
+ private static void writeDataSection(WasmModule module, WasmBinaryWriter writer) throws IOException {
if (module.dataSegments().size() > 0) {
- writeSection(SectionId.DATA, writer, () -> {
- writeVec(
+ writer.writeSection(WasmSectionId.DATA, () -> {
+ writer.writeVec(
module.dataSegments(),
dataSegment -> {
- Leb128Encoding.encodeUnsignedInt32(0x00, writer);
- writeExpression(dataSegment.offset(), writer);
- writeVec(dataSegment.init(), writer);
- },
- writer
+ writer.writeUnsignedInt32(0x00);
+ writeExpression(
+ dataSegment.offset(),
+ writer
+ );
+ writer.writeVec(dataSegment.init());
+ }
);
});
}
@@ -346,7 +322,7 @@ public class WasmBinaryFormatModules {
public static void serializeModule(WasmModule module, OutputStream outputStream) throws IOException {
var indexTable = WasmIndexTable.fromModule(module);
- var writer = new BinaryWriter();
+ var writer = new WasmBinaryWriter();
writer.writeBytes(WASM_MAGIC);
writer.writeBytes(WASM_VERSION);
writeTypeSection(module.types(), writer);
@@ -359,7 +335,7 @@ public class WasmBinaryFormatModules {
writeCodeSection(module, writer);
writeDataSection(module, writer);
writeNameSection(module, indexTable, writer);
- writeLinkingSection(module, indexTable, writer);
+ writeLinkingSections(module, 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 e233cb17..63672039 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
@@ -1,16 +1,12 @@
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.WasmLocal;
import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmModule;
import java.io.IOException;
import java.util.stream.Stream;
-import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatConventions.writeVec;
import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatModules.*;
-import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatSize.writeSize;
-import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatValues.writeString;
public class WasmBinaryFormatNameSection {
// Corresponds to https://webassembly.github.io/spec/core/appendix/custom.html#name-section
@@ -25,7 +21,7 @@ public class WasmBinaryFormatNameSection {
static void writeNameSection(
WasmModule module,
WasmIndexTable indexTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
writeCustomSection("name", writer, () -> {
writeFunctionNameSubsection(module, writer);
@@ -38,12 +34,12 @@ public class WasmBinaryFormatNameSection {
private static void writeNameSubsection(
NameSubsectionId sectionId,
- BinaryWriter writer,
+ WasmBinaryWriter writer,
WasmBinaryFormatModules.Write writeContent
) throws IOException {
writer.writeByte(sectionId.id);
- writeSize(writer, writeContent::write);
+ writer.writeSize(writeContent::write);
}
private enum NameSubsectionId {
@@ -61,15 +57,14 @@ public class WasmBinaryFormatNameSection {
// == Function Names ==
- private static void writeFunctionNameSubsection(WasmModule module, BinaryWriter writer) throws IOException {
+ private static void writeFunctionNameSubsection(WasmModule module, WasmBinaryWriter writer) throws IOException {
writeNameSubsection(NameSubsectionId.FUNCTION_NAMES, writer, () -> {
- writeVec(
+ writer.writeVec(
module.indexedFunctions(),
function -> {
writeFuncIndex(function.funcIndex(), writer);
- writeString(function.name(), writer);
- },
- writer
+ writer.writeString(function.name());
+ }
);
});
}
@@ -79,10 +74,10 @@ public class WasmBinaryFormatNameSection {
private static void writeLocalNameSubsection(
WasmModule module,
WasmIndexTable indexTable,
- BinaryWriter writer
+ WasmBinaryWriter writer
) throws IOException {
writeNameSubsection(NameSubsectionId.LOCAL_NAMES, writer, () -> {
- writeVec(
+ writer.writeVec(
module.indexedFunctionDefinitions(),
indexedFunction -> {
writeFuncIndex(indexedFunction.funcIndex(), writer);
@@ -94,31 +89,28 @@ public class WasmBinaryFormatNameSection {
function.locals().stream()
).map(WasmLocal::name).toList();
- writeVec(
+ writer.writeVec(
names,
(nameIndex, name) -> {
- Leb128Encoding.encodeUnsignedInt32(nameIndex, writer);
- writeString(name, writer);
- },
- writer
+ writer.writeUnsignedInt32(nameIndex);
+ writer.writeString(name);
+ }
);
- },
- writer
+ }
);
});
}
// == Global Names ==
- private static void writeGlobalNameSubsection(WasmModule module, BinaryWriter writer) throws IOException {
+ private static void writeGlobalNameSubsection(WasmModule module, WasmBinaryWriter writer) throws IOException {
writeNameSubsection(NameSubsectionId.GLOBAL_NAMES, writer, () -> {
- writeVec(
+ writer.writeVec(
module.indexedGlobals(),
global -> {
writeGlobalIndex(global.globalIndex(), writer);
- writeString(global.name(), writer);
- },
- writer
+ writer.writeString(global.name());
+ }
);
});
}
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatTypes.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatTypes.java
index 97a8e7db..2ec737f5 100644
--- a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatTypes.java
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatTypes.java
@@ -1,13 +1,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.types.*;
import java.io.IOException;
import java.util.List;
-import static org.shedlang.compiler.backends.wasm.structure.binary.WasmBinaryFormatConventions.writeVec;
-
public class WasmBinaryFormatTypes {
// Corresponds to https://webassembly.github.io/spec/core/binary/types.html
@@ -16,19 +13,19 @@ public class WasmBinaryFormatTypes {
// == Number Types ==
- static void writeNumberType(WasmNumberType type, BinaryWriter writer) {
+ static void writeNumberType(WasmNumberType type, WasmBinaryWriter writer) {
var encoding = switch (type) {
case I32 -> 0x7f;
case I64 -> 0x7e;
case F32 -> 0x7d;
case F64 -> 0x7c;
};
- writer.writeByte((byte) encoding);
+ writer.writeByte(encoding);
}
// == Reference Types ==
- static void writeReferenceType(WasmReferenceType type, BinaryWriter writer) {
+ static void writeReferenceType(WasmReferenceType type, WasmBinaryWriter writer) {
var encoding = switch (type) {
case FUNC_REF -> 0x70;
case EXTERN_REF -> 0x6f;
@@ -38,7 +35,7 @@ public class WasmBinaryFormatTypes {
// == Value Types ==
- static void writeValueType(WasmValueType type, BinaryWriter writer) {
+ static void writeValueType(WasmValueType type, WasmBinaryWriter writer) {
switch (type) {
case WasmValueType.Number number -> {
writeNumberType(number.type(), writer);
@@ -46,51 +43,50 @@ public class WasmBinaryFormatTypes {
}
}
- private static void writeValueTypeVector(List<WasmValueType> types, BinaryWriter writer) throws IOException {
- writeVec(
+ private static void writeValueTypeVector(List<WasmValueType> types, WasmBinaryWriter writer) throws IOException {
+ writer.writeVec(
types,
- type -> writeValueType(type, writer),
- writer
+ type -> writeValueType(type, writer)
);
}
// == Function Types ==
- static void writeFuncType(WasmFuncType type, BinaryWriter writer) throws IOException {
- writer.writeByte((byte) 0x60);
+ static void writeFuncType(WasmFuncType type, WasmBinaryWriter writer) throws IOException {
+ writer.writeByte(0x60);
writeValueTypeVector(type.params(), writer);
writeValueTypeVector(type.results(), writer);
}
// == Limits ==
- static void writeLimits(WasmLimits limits, BinaryWriter writer) {
+ static void writeLimits(WasmLimits limits, WasmBinaryWriter writer) {
if (limits.max().isPresent()) {
writer.writeByte(0x01);
- Leb128Encoding.encodeUnsignedInt32(limits.min(), writer);
- Leb128Encoding.encodeUnsignedInt32(limits.max().getAsInt(), writer);
+ writer.writeUnsignedInt32(limits.min());
+ writer.writeUnsignedInt32(limits.max().getAsInt());
} else {
writer.writeByte(0x00);
- Leb128Encoding.encodeUnsignedInt32(limits.min(), writer);
+ writer.writeUnsignedInt32(limits.min());
}
}
// == Memory Types ==
- static void writeMemoryType(WasmMemoryType type, BinaryWriter writer) {
+ static void writeMemoryType(WasmMemoryType type, WasmBinaryWriter writer) {
writeLimits(type.limits(), writer);
}
// == Table Types ==
- static void writeTableType(WasmTableType type, BinaryWriter writer) {
+ static void writeTableType(WasmTableType type, WasmBinaryWriter writer) {
writeReferenceType(type.elementType(), writer);
writeLimits(type.limits(), writer);
}
// == Global Types ==
- static void writeGlobalType(WasmGlobalType type, BinaryWriter writer) {
+ static void writeGlobalType(WasmGlobalType type, WasmBinaryWriter writer) {
writeValueType(type.valueType(), writer);
var mutabilityEncoding = switch (type.mutability()) {
case MUTABLE -> 0x01;
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryWriter.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryWriter.java
new file mode 100644
index 00000000..0857f4f7
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryWriter.java
@@ -0,0 +1,108 @@
+package org.shedlang.compiler.backends.wasm.structure.binary;
+
+import org.shedlang.compiler.backends.wasm.structure.BinaryWriter;
+import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmMemoryAddress;
+
+import java.io.IOException;
+import java.util.*;
+
+public class WasmBinaryWriter {
+ private final BinaryWriter writer = new BinaryWriter();
+ private final Map<Integer, List<WasmRelocationEntry>> relocationEntries = new HashMap<>();
+ private int sectionIndex = -1;
+ private int sectionContentsStart = -1;
+
+ public void writeByte(int value) {
+ writer.writeByte(value);
+ }
+
+ public void writeBytes(byte[] bytes) {
+ writer.writeBytes(bytes);
+ }
+
+ public void writeUnsignedInt32(int value) {
+ Leb128Encoding.encodeUnsignedInt32(value, writer);
+ }
+
+ public void writePaddedUnsignedInt32(int value) {
+ Leb128Encoding.encodePaddedUnsignedInt32(value, writer);
+ }
+
+ public void writeRelocatableUnsignedInt32(WasmRelocationType relocationType, WasmMemoryAddress index) {
+ // TODO: handle relocatable values in non-CODE sections
+
+ var sectionContentsOffset = writer.position() - sectionContentsStart;
+ writePaddedUnsignedInt32(0);
+
+ if (!relocationEntries.containsKey(sectionIndex)) {
+ relocationEntries.put(sectionIndex, new ArrayList<>());
+ }
+ relocationEntries.get(sectionIndex).add(new WasmRelocationEntry(
+ sectionIndex,
+ relocationType,
+ sectionContentsOffset,
+ index
+ ));
+ }
+
+ public void writeSignedInt32(int value) {
+ Leb128Encoding.encodeSignedInt32(value, writer);
+ }
+
+ public void writeSignedInt64(long value) {
+ Leb128Encoding.encodeSignedInt64(value, writer);
+ }
+
+ public void writeString(String value) {
+ WasmBinaryFormatValues.writeString(value, writer);
+ }
+
+ // TODO: extract write interface
+ public void writeSection(WasmSectionId sectionId, WasmBinaryFormatModules.Write writeContents) throws IOException {
+ sectionIndex++;
+ WasmBinaryFormatModules.writeSection(sectionId, writer, () -> {
+ sectionContentsStart = writer.position();
+ writeContents.write();
+ });
+ }
+
+ public <T> void writeVec(
+ Collection<T> vec,
+ WasmBinaryFormatConventions.WriteElement<T> writeElement
+ ) throws IOException {
+ WasmBinaryFormatConventions.writeVec(
+ vec,
+ writeElement,
+ writer
+ );
+ }
+
+ public <T> void writeVec(
+ List<T> vec,
+ WasmBinaryFormatConventions.WriteIndexedElement<T> writeElement
+ ) throws IOException {
+ WasmBinaryFormatConventions.writeVec(
+ vec,
+ writeElement,
+ writer
+ );
+ }
+
+ public void writeVec(byte[] vec) throws IOException {
+ WasmBinaryFormatConventions.writeVec(vec, writer);
+ }
+
+ public void writeSize(
+ WasmBinaryFormatSize.Write writeContents
+ ) throws IOException {
+ WasmBinaryFormatSize.writeSize(writer, writeContents);
+ }
+
+ public Map<Integer, List<WasmRelocationEntry>> relocationEntries() {
+ return relocationEntries;
+ }
+
+ public byte[] toBytes() {
+ return writer.toBytes();
+ }
+}
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmRelocationEntry.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmRelocationEntry.java
new file mode 100644
index 00000000..fa854748
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmRelocationEntry.java
@@ -0,0 +1,11 @@
+package org.shedlang.compiler.backends.wasm.structure.binary;
+
+import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmMemoryAddress;
+
+public record WasmRelocationEntry(
+ int sectionIndex,
+ WasmRelocationType type,
+ int sectionContentsOffset,
+ WasmMemoryAddress index
+) {
+}
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmRelocationType.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmRelocationType.java
new file mode 100644
index 00000000..1ae3b3dc
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmRelocationType.java
@@ -0,0 +1,39 @@
+package org.shedlang.compiler.backends.wasm.structure.binary;
+
+public enum WasmRelocationType {
+ FUNCTION_INDEX_LEB(0, false),
+ TABLE_INDEX_SLEB(1, true),
+ TABLE_INDEX_I32(2, true),
+ MEMORY_ADDR_LEB(3, false),
+ MEMORY_ADDR_SLEB(4, true),
+ MEMORY_ADDR_I32(5, true),
+ TYPE_INDEX_LEB(6, false),
+ GLOBAL_INDEX_LEB(7, false),
+ FUNCTION_OFFSET_I32(8, true),
+ SECTION_OFFSET_I32(9, true),
+ TAG_INDEX_LEB(10, false),
+ GLOBAL_INDEX_I32(13, true),
+ MEMORY_ADDR_LEB64(14, false),
+ MEMORY_ADDR_SLEB64(15, true),
+ MEMORY_ADDR_I64(16, true),
+ MEMORY_ADDR_REL_SLEB64(17, true),
+ TABLE_INDEX_SLEB64(18, true),
+ TABLE_INDEX_I64(19, true),
+ TABLE_NUMBER_LEB(20, false);
+
+ private final byte id;
+ private final boolean isSigned;
+
+ WasmRelocationType(int id, boolean isSigned) {
+ this.id = (byte) id;
+ this.isSigned = isSigned;
+ }
+
+ public byte id() {
+ return id;
+ }
+
+ public boolean isSigned() {
+ return isSigned;
+ }
+}
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmSectionId.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmSectionId.java
new file mode 100644
index 00000000..8590d41f
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmSectionId.java
@@ -0,0 +1,28 @@
+package org.shedlang.compiler.backends.wasm.structure.binary;
+
+public enum WasmSectionId {
+ CUSTOM(0),
+ TYPE(1),
+ IMPORT(2),
+ FUNCTION(3),
+ TABLE(4),
+ MEMORY(5),
+ GLOBAL(6),
+ EXPORT(7),
+ START(8),
+ ELEMENT(9),
+ CODE(10),
+ DATA(11),
+ DATA_COUNT(12),
+ TAG(13);
+
+ private final byte id;
+
+ WasmSectionId(int id) {
+ this.id = (byte) id;
+ }
+
+ public byte id() {
+ return id;
+ }
+}