diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-06-28 00:26:04 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-06-28 00:26:04 +0100 |
| commit | d64012b950a646bd1d607f73147619ed1f1abbc7 (patch) | |
| tree | 250eb236b90cc620268d2acc22109725a807a41f /src/main/java | |
| parent | 94d8f0318b35658a86e2b4aacad7025dbe2e0ff5 (diff) | |
Hack together support for True example with WASM backend
Diffstat (limited to 'src/main/java')
3 files changed, 140 insertions, 9 deletions
diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java index 89ca9189..48a8d5ee 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java @@ -1,13 +1,18 @@ package org.shedlang.compiler.backends.wasm; import org.shedlang.compiler.backends.Backend; +import org.shedlang.compiler.backends.wasm.structure.WasmBinaryFormat; +import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmModule; import org.shedlang.compiler.config.ProjectConfig; import org.shedlang.compiler.stackir.instructions.Instruction; import org.shedlang.compiler.typechecker.TypeInfo; import org.shedlang.compiler.types.NamespaceName; +import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -19,11 +24,74 @@ public class WasmBackend implements Backend { TypeInfo typeInfo, Path targetDir ) throws IOException { + var objectFilePaths = new ArrayList<Path>(); + for (var namespace : namespaces.entrySet()) { + var namespaceName = namespace.getKey(); + var wasmModule = WasmCodeGen.generateNamespace( + namespaceName, + namespace.getValue(), + typeInfo + ); + var objectPath = writeObjectFile( + wasmModule, + targetDir.resolve("namespaces"), + String.join("_", namespaceName.parts()) + ); + objectFilePaths.add(objectPath); + } + + for (var bin : config.bins()) { + var ldArgs = new ArrayList<String>(); + ldArgs.add("wasm-ld"); + + ldArgs.add("-o"); + ldArgs.add(targetDir.resolve(bin.name() + ".wasm").toString()); + + for (var objectFilePath : objectFilePaths) { + ldArgs.add(objectFilePath.toString()); + } + + var mainModule = WasmCodeGen.generateMain(config.main(), typeInfo); + var mainObjectPath = writeObjectFile(mainModule, targetDir.resolve("bins"), bin.name()); + ldArgs.add(mainObjectPath.toString()); + + run(ldArgs); + } } @Override public String name() { return "wasm"; } + + private static Path writeObjectFile(WasmModule module, Path workingDirectory, String name) throws IOException { + var objectPath = workingDirectory.resolve(name + ".o"); + Files.createDirectories(objectPath.getParent()); + try (var outputStream = new FileOutputStream(objectPath.toFile())) { + WasmBinaryFormat.serializeModule(module, outputStream); + } + return objectPath; + } + + // TODO: extract common run() code + private static void run(List<String> args) throws IOException { + var process = new ProcessBuilder(args) + .inheritIO() + .start(); + + while (true) { + try { + var exitCode = process.waitFor(); + if (exitCode != 0) { + // TODO: better error code + throw new RuntimeException("exit code: " + exitCode); + } else { + return; + } + } catch (InterruptedException exception) { + + } + } + } } 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 88d46346..844a2347 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java @@ -1,11 +1,16 @@ package org.shedlang.compiler.backends.wasm; import org.shedlang.compiler.backends.wasm.structure.ast.instructions.*; +import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmFunction; import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmLocalIndex; +import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmModule; import org.shedlang.compiler.stackir.instructions.*; +import org.shedlang.compiler.typechecker.TypeInfo; +import org.shedlang.compiler.types.NamespaceName; import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; import static org.shedlang.compiler.util.Lists.reversed; @@ -14,6 +19,42 @@ public class WasmCodeGen { private WasmCodeGen() { } + public static WasmModule generateMain(NamespaceName main, TypeInfo typeInfo) { + var context = WasmCodeGenContext.fromTypeInfo(typeInfo); + + context = context.addFunction(new WasmFunction( + "_start", + List.of(), + List.of(), + List.of(), + new WasmExpression(List.of()) + )); + + return context.toModule(); + } + + public static WasmModule generateNamespace( + NamespaceName namespaceName, + List<Instruction> instructions, + TypeInfo typeInfo + ) { + var context = WasmCodeGenContext.fromTypeInfo(typeInfo); + + context = WasmCodeGenNamespaces.define( + namespaceName, + initContext -> { + for (var instruction : instructions) { + initContext = generateInstruction(instruction, initContext); + } + + return initContext; + }, + context + ); + + return context.toModule(); + } + public static WasmCodeGenContext generateInstruction(Instruction instruction, WasmCodeGenContext context) { return switch (instruction) { case CallInstruction call -> { diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenNamespaces.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenNamespaces.java index 38f57f52..a1fdb0fc 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenNamespaces.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenNamespaces.java @@ -9,10 +9,35 @@ import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmAlignment; import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmLocalIndex; import org.shedlang.compiler.types.NamespaceName; +import java.util.function.Function; + public class WasmCodeGenNamespaces { private WasmCodeGenNamespaces() { } + public static WasmCodeGenContext define( + NamespaceName namespaceName, + Function<WasmCodeGenContext, WasmCodeGenContext> generateInitBody, + WasmCodeGenContext context + ) { + var namespaceTypeInfo = context.typeInfo().namespaceTypeInfo(namespaceName); + + var dataName = globalNameNamespaceValue(namespaceName); + + context = context.addData( + dataName, + // TODO: remove magic number + new byte[4 * namespaceTypeInfo.fieldCount()], + WasmAlignment.ALIGN_32_BIT + ).context(); + + context = generateInitBody.apply(context); + + var namespaceInitFunction = context.toFunction(globalNameNamespaceInit(namespaceName)); + + return context.addFunction(namespaceInitFunction); + } + public static WasmCodeGenContext fieldStore( NamespaceName namespaceName, String fieldName, @@ -34,21 +59,18 @@ public class WasmCodeGenNamespaces { } private static WasmMemoryAddress namespaceMemoryAddress(NamespaceName namespaceName, WasmCodeGenContext context) { - var dataName = dataNameNamespaceValue(namespaceName); + var dataName = globalNameNamespaceValue(namespaceName); return context.memoryAddress(dataName); - -// context.addData( -// dataName, -// // TODO: remove magic number -// new byte[4 * ], -// WasmAlignment.ALIGN_32_BIT -// ); } - private static String dataNameNamespaceValue(NamespaceName namespaceName) { + private static String globalNameNamespaceValue(NamespaceName namespaceName) { return "shed__namespace__" + namespaceNameToWasmIdentifier(namespaceName); } + private static String globalNameNamespaceInit(NamespaceName namespaceName) { + return "shed__namespaceInit__" + namespaceNameToWasmIdentifier(namespaceName); + } + private static String namespaceNameToWasmIdentifier(NamespaceName namespaceName) { return String.join("_", namespaceName.parts()); } |
