From 4ce47e845323f67bb3a6e3ef1c6314eb459d7622 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 16 Sep 2023 15:27:56 +0100 Subject: Remove direct WASM backend --- .../org/shedlang/compiler/backends/Backends.java | 3 +- .../compiler/backends/wasm/WasmBackend.java | 133 +++--- .../compiler/backends/wasm/WasmCodeGen.java | 295 ------------- .../compiler/backends/wasm/WasmCodeGenAlloc.java | 32 -- .../backends/wasm/WasmCodeGenClosures.java | 167 ------- .../compiler/backends/wasm/WasmCodeGenContext.java | 485 --------------------- .../backends/wasm/WasmCodeGenGlobalSpace.java | 18 - .../backends/wasm/WasmCodeGenLocalSpace.java | 25 -- .../backends/wasm/WasmCodeGenNamespaces.java | 167 ------- .../compiler/backends/wasm/WasmCodeGenResult.java | 4 - .../compiler/backends/wasm/WasmCodeGenStrings.java | 54 --- .../compiler/backends/wasm/WasmCodeGenTypes.java | 11 - 12 files changed, 50 insertions(+), 1344 deletions(-) delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenAlloc.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenClosures.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenGlobalSpace.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenLocalSpace.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenNamespaces.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenResult.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java delete mode 100644 src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenTypes.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/backends/Backends.java b/src/main/java/org/shedlang/compiler/backends/Backends.java index 4d53cee8..dfc8925c 100644 --- a/src/main/java/org/shedlang/compiler/backends/Backends.java +++ b/src/main/java/org/shedlang/compiler/backends/Backends.java @@ -10,6 +10,5 @@ public class Backends { public static final OrderedPMap BACKENDS = OrderedPMap.empty() .plus("llvm", LlvmBackend.INSTANCE) - .plus("wasm", WasmBackend.DIRECT) - .plus("wasm-patio", WasmBackend.PATIO); + .plus("wasm", WasmBackend.INSTANCE); } 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 584d8832..8c3bc338 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java @@ -24,86 +24,11 @@ import java.util.List; import static org.shedlang.compiler.util.processes.ProcessRunner.runInheritIo; public class WasmBackend implements Backend { - public static final WasmBackend DIRECT = new WasmBackend("wasm", new CodeGen() { - @Override - public WasmModule generateNamespace(StackIrNamespace stackIrNamespace, TypeInfo typeInfo) { - return WasmCodeGen.generateNamespace(stackIrNamespace, typeInfo); - } - - @Override - public WasmModule generateMain(NamespaceName main, TypeInfo typeInfo) { - return WasmCodeGen.generateMain(main, typeInfo); - } - }); - - public static final WasmBackend PATIO = new WasmBackend("wasm-patio", new CodeGen() { - @Override - public WasmModule generateNamespace(StackIrNamespace stackIrNamespace, TypeInfo typeInfo) { - var patioCompilationUnit = PatioCodeGen.generateNamespace( - stackIrNamespace, - PatioCodeGenContext.forTypeInfo(typeInfo) - ); - - return WasmPatioCodeGen.generateCompilationUnit(patioCompilationUnit); - } - - @Override - public WasmModule generateMain(NamespaceName main, TypeInfo typeInfo) { - // TODO: set appropriate source - var source = Sources.NULL; - - var context = PatioCodeGenContext.forTypeInfo(typeInfo); - - var generateMainResult = PatioCodeGen.generateMain(main, source, context); - var mainFunctionName = generateMainResult.value(); - context = generateMainResult.context(); - - var patioCompilationUnit = context.toCompilationUnit(source); - - var wasmModule = WasmPatioCodeGen.generateCompilationUnit(patioCompilationUnit); + public static final WasmBackend INSTANCE = new WasmBackend(); - // TODO: put these in separate module, remove duplication - wasmModule = wasmModule.addFunction(new WasmFunction( - "wasm_memory_grow", - List.of(new WasmLocal("pages", WasmValueType.I32)), - List.of(), - List.of(WasmValueType.I32), - new WasmExpression(List.of( - new WasmLocalGet(new WasmLocalIndex(0)), - new WasmMemoryGrow() - )) - )); - - wasmModule = wasmModule.addFunction(new WasmFunction( - "_start", - List.of(), - List.of(), - List.of(), - new WasmExpression(List.of( - new WasmCall(new WasmFuncName(mainFunctionName)), - new WasmDrop() - )) - )); - - return wasmModule; - } - }); - - interface CodeGen { - WasmModule generateNamespace( - StackIrNamespace stackIrNamespace, - TypeInfo typeInfo - ); - - WasmModule generateMain(NamespaceName main, TypeInfo typeInfo); - } - - private final String name; - private final CodeGen codeGen; - - private WasmBackend(String name, CodeGen codeGen) { - this.name = name; - this.codeGen = codeGen; + @Override + public String name() { + return "patio"; } @Override @@ -115,7 +40,12 @@ public class WasmBackend implements Backend { ) throws IOException, InterruptedException { var objectFilePaths = new ArrayList(); for (var namespace : namespaces) { - var wasmModule = this.codeGen.generateNamespace(namespace, typeInfo); + var patioCompilationUnit = PatioCodeGen.generateNamespace( + namespace, + PatioCodeGenContext.forTypeInfo(typeInfo) + ); + + var wasmModule = WasmPatioCodeGen.generateCompilationUnit(patioCompilationUnit); var objectPath = writeObjectFile( wasmModule, @@ -136,7 +66,7 @@ public class WasmBackend implements Backend { ldArgs.add(objectFilePath.toString()); } - var mainModule = this.codeGen.generateMain(config.main(), typeInfo); + var mainModule = this.generateMain(config.main(), typeInfo); var mainObjectPath = writeObjectFile(mainModule, targetDir.resolve("bins"), bin.name()); ldArgs.add(mainObjectPath.toString()); @@ -146,9 +76,44 @@ public class WasmBackend implements Backend { } } - @Override - public String name() { - return name; + private WasmModule generateMain(NamespaceName main, TypeInfo typeInfo) { + // TODO: set appropriate source + var source = Sources.NULL; + + var context = PatioCodeGenContext.forTypeInfo(typeInfo); + + var generateMainResult = PatioCodeGen.generateMain(main, source, context); + var mainFunctionName = generateMainResult.value(); + context = generateMainResult.context(); + + var patioCompilationUnit = context.toCompilationUnit(source); + + var wasmModule = WasmPatioCodeGen.generateCompilationUnit(patioCompilationUnit); + + // TODO: put these in separate module, remove duplication + wasmModule = wasmModule.addFunction(new WasmFunction( + "wasm_memory_grow", + List.of(new WasmLocal("pages", WasmValueType.I32)), + List.of(), + List.of(WasmValueType.I32), + new WasmExpression(List.of( + new WasmLocalGet(new WasmLocalIndex(0)), + new WasmMemoryGrow() + )) + )); + + wasmModule = wasmModule.addFunction(new WasmFunction( + "_start", + List.of(), + List.of(), + List.of(), + new WasmExpression(List.of( + new WasmCall(new WasmFuncName(mainFunctionName)), + new WasmDrop() + )) + )); + + return wasmModule; } private static Path writeObjectFile(WasmModule module, Path workingDirectory, String name) throws IOException { diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java deleted file mode 100644 index 431ebc1d..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java +++ /dev/null @@ -1,295 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -import org.shedlang.compiler.backends.wasm.structure.ast.instructions.*; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmLocalIndex; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmModule; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmFuncType; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmValueType; -import org.shedlang.compiler.stackir.StackIrNamespace; -import org.shedlang.compiler.stackir.instructions.*; -import org.shedlang.compiler.typechecker.TypeInfo; -import org.shedlang.compiler.types.NamespaceName; -import org.shedlang.compiler.util.Lists; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.shedlang.compiler.util.Lists.reversed; - -public class WasmCodeGen { - private WasmCodeGen() { - } - - public static WasmModule generateMain(NamespaceName main, TypeInfo typeInfo) { - var context = WasmCodeGenContext.fromTypeInfo(typeInfo); - - // TODO: put these in a separate module - context = context.createFunction( - "wasm_memory_grow", - new WasmFuncType(List.of(WasmValueType.I32), List.of(WasmValueType.I32)), - bodyContext -> { - return bodyContext - .generateLocal(WasmCodeGenLocalSpace.LOCAL, "pages").context() - .addInstruction(new WasmLocalGet(new WasmLocalIndex(0))) - .addInstruction(new WasmMemoryGrow()); - } - ); - - context = context.createFunction( - "_start", - new WasmFuncType(List.of(), List.of()), - mainContext -> { - var namespaceResult = mainContext.generateLocal( - WasmCodeGenLocalSpace.NAMESPACE, - WasmCodeGenNamespaces.namespaceNameToWasmIdentifier(main) - ); - var namespace = namespaceResult.value(); - mainContext = namespaceResult.context(); - - mainContext = WasmCodeGenNamespaces.importValue(main, mainContext); - mainContext = mainContext.addInstruction(new WasmLocalSet(namespace)); - - var fieldResult = mainContext.generateLocal( - WasmCodeGenLocalSpace.MAIN - ); - var field = fieldResult.value(); - mainContext = fieldResult.context(); - - mainContext = WasmCodeGenNamespaces.fieldLoad( - main, - namespace, - // TODO: check there is a main function - "main", - mainContext - ); - mainContext = mainContext.addInstruction(new WasmLocalSet(field)); - - // TODO: make code gen functions consistent in whether they - // return locals or put values on the stack - mainContext = WasmCodeGenClosures.call( - field, - List.of(), - List.of(), - mainContext - ); - mainContext = mainContext.addInstruction(new WasmDrop()); - - return mainContext; - } - ); - - return context.toModule(); - } - - public static WasmModule generateNamespace( - StackIrNamespace namespace, - TypeInfo typeInfo - ) { - var context = WasmCodeGenContext.fromTypeInfo(typeInfo); - - context = WasmCodeGenNamespaces.define( - namespace.namespaceName(), - initContext -> { - for (var instruction : namespace.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 -> { - var namedArgsByName = new ArrayList>(); - for (var argName : reversed(call.namedArgNames())) { - var argResult = context.generateLocal( - WasmCodeGenLocalSpace.CALL_ARG_NAMED, - argName - ); - var arg = argResult.value(); - context = argResult.context(); - - context = context.addInstruction(new WasmLocalSet(arg)); - - namedArgsByName.add(Map.entry(argName, arg)); - } - - var positionalArgs = new ArrayList(); - for (var i = 0; i < call.positionalArgCount(); i++) { - var argResult = context.generateLocal( - WasmCodeGenLocalSpace.CALL_ARG_POSITIONAL, - Integer.toString(call.positionalArgCount() - i - 1) - ); - var arg = argResult.value(); - context = argResult.context(); - - context = context.addInstruction(new WasmLocalSet(arg)); - - positionalArgs.add(arg); - } - Collections.reverse(positionalArgs); - - var receiverResult = context.generateLocal(WasmCodeGenLocalSpace.RECEIVER); - var receiver = receiverResult.value(); - context = receiverResult.context(); - - context = context.addInstruction(new WasmLocalSet(receiver)); - - yield WasmCodeGenClosures.call( - receiver, - positionalArgs, - namedArgsByName, - context - ); - } - case DefineFunctionInstruction defineFunction -> - WasmCodeGenClosures.create( - defineFunction.name(), - defineFunction.positionalParams(), - defineFunction.namedParams(), - defineFunction.freeVariables(), - functionContext -> { - functionContext = generateInstructions(defineFunction.body(), functionContext); - return functionContext; - }, - context - ); - - case DiscardInstruction discard -> - context.addInstruction(new WasmDrop()); - - case FieldLoadInstruction fieldLoad -> { - var receiverResult = context.generateLocal(WasmCodeGenLocalSpace.RECEIVER); - var receiver = receiverResult.value(); - context = receiverResult.context(); - - context = context.addInstruction(new WasmLocalSet(receiver)); - - yield WasmCodeGenNamespaces.fieldLoad( - fieldLoad.namespaceName(), - receiver, - fieldLoad.fieldName(), - context - ); - } - - case IfInstruction if_ -> { - context = context.enterBlock(); - context = generateInstructions(if_.trueBody(), context); - var trueBodyResult = context.exitBlock(); - var trueBody = trueBodyResult.value(); - context = trueBodyResult.context(); - - context = context.enterBlock(); - context = generateInstructions(if_.falseBody(), context); - var falseBodyResult = context.exitBlock(); - var falseBody = falseBodyResult.value(); - context = falseBodyResult.context(); - - yield context.addInstruction(new WasmIf( - new WasmBlockType(Lists.repeat(WasmCodeGenTypes.VALUE_TYPE, if_.resultCount())), - trueBody, - falseBody - )); - } - - case IntAddInstruction intAdd -> - context.addInstruction(new WasmI32Add()); - - case IntEqualsInstruction intEquals -> - context.addInstruction(new WasmI32Eq()); - - case IntNotEqualInstruction intNotEqual -> - context.addInstruction(new WasmI32Ne()); - - case IntSubInstruction intSub -> - context.addInstruction(new WasmI32Sub()); - - case LocalLoadInstruction localLoad -> - context.addInstruction(new WasmLocalGet(context.shedLocal(localLoad.name()))); - - case LocalStoreInstruction localStore -> { - yield context.addShedLocal( - localStore.name(), - (local, c) -> c.addInstruction(new WasmLocalSet(local)) - ); - } - - case LoopInstruction loop -> - throw new UnsupportedOperationException("TODO"); - - case LoopBreakInstruction loopBreak -> - throw new UnsupportedOperationException("TODO"); - - case LoopContinueInstruction loopContinue -> - throw new UnsupportedOperationException("TODO"); - - case NamespaceFieldStoreInstruction namespaceFieldStore -> { - var fieldValueResult = context.generateLocal( - WasmCodeGenLocalSpace.FIELD_VALUE, - namespaceFieldStore.fieldName() - ); - var fieldValue = fieldValueResult.value(); - context = fieldValueResult.context(); - - context = context.addInstruction(new WasmLocalSet(fieldValue)); - - yield WasmCodeGenNamespaces.fieldStore( - namespaceFieldStore.namespaceName(), - namespaceFieldStore.fieldName(), - fieldValue, - context - ); - } - - case NamespaceImportInstruction namespaceImport -> - WasmCodeGenNamespaces.importValue(namespaceImport.namespaceName(), context); - - case PushBoolInstruction pushBool -> - context.addInstruction(new WasmI32Const(pushBool.value() ? 1 : 0)); - - case PushIntInstruction pushInt -> - context.addInstruction(new WasmI32Const(pushInt.value().intValueExact())); - - case PushStringInstruction pushString -> { - var defineStringResult = WasmCodeGenStrings.defineString(pushString.value(), context); - var offset = defineStringResult.value(); - context = defineStringResult.context(); - - yield context.addInstruction(new WasmMemoryAddressConst(offset)); - } - - case PushUnitInstruction pushUnit -> - context.addInstruction(new WasmI32Const(0)); - - case ReturnInstruction returnInstruction -> - context.addInstruction(new WasmReturn()); - - case StringAddInstruction stringAdd -> - WasmCodeGenStrings.add(context); - - case VarLoadInstruction varLoad -> - throw new UnsupportedOperationException(); - - case VarStoreInstruction varStore -> - throw new UnsupportedOperationException(); - }; - } - - private static WasmCodeGenContext generateInstructions( - List instructions, - WasmCodeGenContext context - ) { - for (var instruction : instructions) { - context = generateInstruction(instruction, context); - } - return context; - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenAlloc.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenAlloc.java deleted file mode 100644 index 96363570..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenAlloc.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmCall; -import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmI32Const; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmFuncName; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmImport; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmImportDescriptor; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmFuncType; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmValueType; - -import java.util.List; - -public class WasmCodeGenAlloc { - private WasmCodeGenAlloc() { - } - - public static WasmCodeGenContext callAlloc(int size, WasmCodeGenContext context) { - var allocName = "shed__runtime__alloc"; - - return context - .addImport(new WasmImport( - "env", - allocName, - new WasmImportDescriptor.Func( - allocName, - new WasmFuncType(List.of(WasmValueType.I32), List.of(WasmValueType.I32)) - ) - )) - .addInstruction(new WasmI32Const(size)) - .addInstruction(new WasmCall(new WasmFuncName(allocName))); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenClosures.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenClosures.java deleted file mode 100644 index be7406bb..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenClosures.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -import org.shedlang.compiler.ast.typed.FreeVariable; -import org.shedlang.compiler.ast.typed.FreeVariables; -import org.shedlang.compiler.backends.wasm.structure.ast.instructions.*; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmAlignment; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmFuncName; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmLocalIndex; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmFuncType; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmValueType; -import org.shedlang.compiler.stackir.instructions.DefineFunctionInstruction; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Stream; - -import static org.shedlang.compiler.util.Iterables.sortedBy; - -public class WasmCodeGenClosures { - private WasmCodeGenClosures() { - } - - private static final WasmValueType CLOSURE_TYPE = WasmValueType.I32; - - public static WasmCodeGenContext create( - String name, - List positionalParams, - List namedParams, - FreeVariables freeVariables, - Function compileBody, - WasmCodeGenContext context - ) { - var functionName = context.generateFunctionName( - WasmCodeGenGlobalSpace.FUNCTION, - name - ); - - var shedParams = Stream.concat(positionalParams.stream(), namedParams.stream()).toList(); - - var wasmParamTypes = new ArrayList(); - wasmParamTypes.add(CLOSURE_TYPE); - for (var shedParam : shedParams) { - wasmParamTypes.add(WasmCodeGenTypes.VALUE_TYPE); - } - - var closureFuncType = new WasmFuncType( - wasmParamTypes, - List.of(WasmCodeGenTypes.VALUE_TYPE) - ); - - context = context.createFunction(functionName, closureFuncType, bodyContext -> { - var closurePointerResult = bodyContext.generateLocal(WasmCodeGenLocalSpace.CLOSURE_POINTER); - var closurePointer = closurePointerResult.value(); - bodyContext = closurePointerResult.context(); - - for (var shedParam : shedParams) { - bodyContext = bodyContext.addShedArg(shedParam.name()); - } - - for (var freeVariable : freeVariables) { - bodyContext = bodyContext.addShedLocal( - freeVariable.name(), - (freeVariableIndex, c) -> c - .addInstruction(new WasmLocalGet(closurePointer)) - .addInstruction(new WasmI32Load(freeVariableMemoryArg(freeVariable))) - .addInstruction(new WasmLocalSet(freeVariableIndex)) - ); - } - - bodyContext = compileBody.apply(bodyContext); - - return bodyContext; - }); - - var closurePointerResult = context.generateLocal(WasmCodeGenLocalSpace.CLOSURE_POINTER); - var closurePointer = closurePointerResult.value(); - context = closurePointerResult.context(); - - // TODO: remove magic numbers - var closureSize = 4 + freeVariables.size() * 4; - context = WasmCodeGenAlloc.callAlloc(closureSize, context); - context = context.addInstruction(new WasmLocalSet(closurePointer)); - - context = context - .addInstruction(new WasmLocalGet(closurePointer)) - .addInstruction(new WasmTableElementIndexConst(new WasmFuncName(functionName))) - .addInstruction(new WasmI32Store(functionPointerMemoryArg())); - - for (var freeVariable : freeVariables) { - // TODO: test behaviour when local is defined later - context = context.onceShedLocalDefined( - freeVariable.name(), - c -> c - .addInstruction(new WasmLocalGet(closurePointer)) - .addInstruction(new WasmLocalGet(c.shedLocal(freeVariable.name()))) - .addInstruction(new WasmI32Store(freeVariableMemoryArg(freeVariable))) - ); - } - - context = context.addInstruction(new WasmLocalGet(closurePointer)); - - return context; - } - - private static WasmMemoryArg functionPointerMemoryArg() { - return new WasmMemoryArg( - // TODO: remove magic numbers - 0, - WasmAlignment.ALIGN_32_BIT - ); - } - - private static WasmMemoryArg freeVariableMemoryArg(FreeVariable freeVariable) { - return new WasmMemoryArg( - // TODO: remove magic numbers - 4 + freeVariable.index() * 4, - WasmAlignment.ALIGN_32_BIT - ); - } - - public static WasmCodeGenContext call( - WasmLocalIndex closure, - List positionalArgs, - List> namedArgsByName, - WasmCodeGenContext context - ) { - context = context.addInstruction(new WasmLocalGet(closure)); - - for (var positionalArg : positionalArgs) { - context = context.addInstruction(new WasmLocalGet(positionalArg)); - } - - for (var namedArg : sortedBy(namedArgsByName, x -> x.getKey())) { - context = context.addInstruction(new WasmLocalGet(namedArg.getValue())); - } - - context = loadClosureFunctionTableIndex(closure, context); - - var paramTypes = new ArrayList(); - paramTypes.add(CLOSURE_TYPE); - - var argCount = positionalArgs.size() + namedArgsByName.size(); - for (var i = 0; i < argCount; i++) { - paramTypes.add(WasmCodeGenTypes.VALUE_TYPE); - } - - var funcType = new WasmFuncType( - paramTypes, - List.of(WasmCodeGenTypes.VALUE_TYPE) - ); - - return context - .addType(funcType) - .addInstruction(new WasmCallIndirect(context.indirectFunctionTableIndex(), funcType)); - } - - private static WasmCodeGenContext loadClosureFunctionTableIndex( - WasmLocalIndex closure, - WasmCodeGenContext context - ) { - return context - .addInstruction(new WasmLocalGet(closure)) - .addInstruction(new WasmI32Load(functionPointerMemoryArg())); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java deleted file mode 100644 index c533763c..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenContext.java +++ /dev/null @@ -1,485 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -import org.pcollections.*; -import org.shedlang.compiler.backends.NameAllocator; -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.linking.WasmMemoryAddress; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.*; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmFuncType; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmLimits; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmReferenceType; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmTableType; -import org.shedlang.compiler.typechecker.TypeInfo; -import org.shedlang.compiler.util.P; - -import java.util.List; -import java.util.Optional; -import java.util.function.BiFunction; -import java.util.function.Function; - -public record WasmCodeGenContext( - ModuleContext moduleContext, - FunctionContext functionContext -) { - record ModuleContext( - TypeInfo typeInfo, - OrderedPSet types, - OrderedPSet imports, - PVector functions, - PVector globals, - PSet symbolNames, - WasmMemoryBuilder memory - ) { - public static final ModuleContext EMPTY = new ModuleContext( - TypeInfo.EMPTY, - OrderedPSet.empty(), - OrderedPSet.empty(), - Empty.vector(), - Empty.vector(), - Empty.set(), - WasmMemoryBuilder.EMPTY - ); - - public static ModuleContext fromTypeInfo(TypeInfo typeInfo) { - return new ModuleContext( - typeInfo, - OrderedPSet.empty(), - OrderedPSet.empty(), - Empty.vector(), - Empty.vector(), - Empty.set(), - WasmMemoryBuilder.EMPTY - ); - } - - public ModuleContext addType(WasmFuncType funcType) { - return new ModuleContext( - this.typeInfo, - this.types.plus(funcType), - this.imports, - this.functions, - this.globals, - this.symbolNames, - this.memory - ); - } - - public ModuleContext addImport(WasmImport import_) { - return new ModuleContext( - this.typeInfo, - this.types, - this.imports.plus(import_), - this.functions, - this.globals, - this.symbolNames, - this.memory - ); - } - - public ModuleContext addFunction(WasmFunction function) { - return new ModuleContext( - this.typeInfo, - this.types.plus(function.type()), - this.imports, - this.functions.plus(function), - this.globals, - this.symbolNames.plus(function.name()), - this.memory - ); - } - - public ModuleContext addGlobal(WasmGlobal global) { - return new ModuleContext( - this.typeInfo, - this.types, - this.imports, - this.functions, - this.globals.plus(global), - this.symbolNames.plus(global.name()), - this.memory - ); - } - - public String generateSymbolName(WasmCodeGenGlobalSpace space, Optional name) { - return NameAllocator.allocateName( - symbolNames::contains, - "shed__" + space, - name - ); - } - - public Result addData( - String name, - byte[] data, - WasmAlignment alignment - ) { - var result = memory.add(name, data, alignment); - - return new ModuleContext( - this.typeInfo, - this.types, - this.imports, - this.functions, - this.globals, - this.symbolNames.plus(name), - result.memory() - ).toResult(result.offset()); - } - - public WasmModule toModule() { - var module = WasmModule.EMPTY; - - module = module.addImport(new WasmImport( - "env", - "__indirect_function_table", - new WasmImportDescriptor.Table(new WasmTableType( - WasmReferenceType.FUNC_REF, - // TODO: set size according to number of entries - WasmLimits.min(0) - )) - )); - - for (var import_ : imports) { - module = module.addImport(import_); - } - - for (var type : types) { - module = module.addType(type); - } - - for (var function : functions) { - module = module.addFunction(function); - } - - for (var global : globals) { - module = module.addGlobal(global); - } - - return memory.toModule(module); - } - - public Result toResult(T value) { - return new Result<>(value, this); - } - - record Result(T value, ModuleContext context) { - } - } - - record FunctionContext( - WasmFuncType funcType, - PVector instructions, - PStack> blockStack, - OrderedPMap locals, - PMap shedLocalNameToLocalIndex, - PMap>> waitingForShedLocal - ) { - public static final FunctionContext EMPTY = forFuncType( - new WasmFuncType(List.of(), List.of()) - ); - - public static FunctionContext forFuncType(WasmFuncType funcType) { - return new FunctionContext( - funcType, - Empty.vector(), - Empty.stack(), - OrderedPMap.empty(), - Empty.map(), - Empty.map() - ); - } - - public FunctionContext addInstruction(WasmInstruction instruction) { - return new FunctionContext( - this.funcType, - this.instructions.plus(instruction), - this.blockStack, - this.locals, - this.shedLocalNameToLocalIndex, - this.waitingForShedLocal - ); - } - - public FunctionContext enterBlock() { - return new FunctionContext( - this.funcType, - P.vector(), - this.blockStack.plus(this.instructions), - this.locals, - this.shedLocalNameToLocalIndex, - this.waitingForShedLocal - ); - } - - public Result> exitBlock() { - return new FunctionContext( - this.funcType, - this.blockStack.get(0), - this.blockStack.minus(0), - this.locals, - this.shedLocalNameToLocalIndex, - this.waitingForShedLocal - ).toResult(this.instructions); - } - - public Result generateLocal(WasmCodeGenLocalSpace space, Optional name) { - var localIndex = new WasmLocalIndex(locals.size()); - var localName = NameAllocator.allocateName( - x -> locals.containsKey(x), - space, - name - ); - return new FunctionContext( - this.funcType, - this.instructions, - this.blockStack, - this.locals.plus( - localName, - new WasmLocal(localName, WasmCodeGenTypes.VALUE_TYPE) - ), - this.shedLocalNameToLocalIndex, - this.waitingForShedLocal - ).toResult(localIndex); - } - - public Result>> addShedLocal(String name) { - var localIndexResult = generateLocal(WasmCodeGenLocalSpace.LOCAL, Optional.of(name)); - var localIndex = localIndexResult.value(); - var context = localIndexResult.context(); - - var funcs = this.waitingForShedLocal.getOrDefault(name, P.vector()); - - return new FunctionContext( - context.funcType, - context.instructions, - context.blockStack, - context.locals, - context.shedLocalNameToLocalIndex.plus(name, localIndex), - this.waitingForShedLocal.minus(name) - ).toResult(funcs); - } - - public Optional shedLocalOrNone(String name) { - return Optional.ofNullable(shedLocalNameToLocalIndex.get(name)); - } - - public WasmLocalIndex shedLocal(String name) { - var localIndex = shedLocalNameToLocalIndex.get(name); - if (localIndex == null) { - // TODO: throw better error - throw new RuntimeException("unknown local: " + name); - } else { - return localIndex; - } - } - - public FunctionContext addWaitingForShedLocal( - String name, - Function func - ) { - return new FunctionContext( - this.funcType, - this.instructions, - this.blockStack, - this.locals, - this.shedLocalNameToLocalIndex, - this.waitingForShedLocal.plus( - name, - this.waitingForShedLocal.getOrDefault(name, P.vector()).plus(func) - ) - ); - } - - public WasmFunction toFunction(String name) { - return new WasmFunction( - name, - locals.values().stream().limit(funcType.params().size()).toList(), - locals.values().stream().skip(funcType.params().size()).toList(), - funcType.results(), - new WasmExpression(instructions) - ); - } - - public Result toResult(T value) { - return new Result<>(value, this); - } - - record Result(T value, FunctionContext context) { - } - } - - public static final WasmCodeGenContext EMPTY = new WasmCodeGenContext( - ModuleContext.EMPTY, - FunctionContext.EMPTY - ); - - public static WasmCodeGenContext fromTypeInfo(TypeInfo typeInfo) { - return new WasmCodeGenContext( - ModuleContext.fromTypeInfo(typeInfo), - FunctionContext.EMPTY - ); - } - - public TypeInfo typeInfo() { - return moduleContext.typeInfo; - } - - public WasmCodeGenContext addType(WasmFuncType funcType) { - return new WasmCodeGenContext( - this.moduleContext.addType(funcType), - this.functionContext - ); - } - - public WasmCodeGenContext addImport(WasmImport import_) { - return new WasmCodeGenContext( - this.moduleContext.addImport(import_), - this.functionContext - ); - } - - public String generateFunctionName(WasmCodeGenGlobalSpace space, String name) { - return moduleContext.generateSymbolName(space, Optional.of(name)); - } - - public String generateGlobalName(WasmCodeGenGlobalSpace space) { - return moduleContext.generateSymbolName(space, Optional.empty()); - } - - public WasmCodeGenContext addFunction(WasmFunction function) { - return new WasmCodeGenContext( - this.moduleContext.addFunction(function), - this.functionContext - ); - } - - public WasmCodeGenContext addGlobal(WasmGlobal global) { - return new WasmCodeGenContext( - this.moduleContext.addGlobal(global), - this.functionContext - ); - } - - public WasmCodeGenResult addData( - String name, - byte[] data, - WasmAlignment alignment - ) { - var result = this.moduleContext.addData(name, data, alignment); - - return new WasmCodeGenContext( - result.context, - this.functionContext - ).toResult(result.value); - } - - public WasmModule toModule() { - return moduleContext.toModule(); - } - - public WasmCodeGenContext addInstruction(WasmInstruction instruction) { - return new WasmCodeGenContext( - this.moduleContext, - this.functionContext.addInstruction(instruction) - ); - } - - public WasmCodeGenContext enterBlock() { - return new WasmCodeGenContext( - this.moduleContext, - this.functionContext.enterBlock() - ); - } - - public WasmCodeGenResult> exitBlock() { - var exitResult = this.functionContext.exitBlock(); - - return new WasmCodeGenContext( - this.moduleContext, - exitResult.context - ).toResult(exitResult.value); - } - - public WasmFunction toFunction(String name) { - return this.functionContext.toFunction(name); - } - - public WasmCodeGenContext addShedArg(String name) { - return addShedLocal(name, (l, c) -> c); - } - - public WasmCodeGenContext addShedLocal( - String name, - BiFunction setLocal - ) { - var result = this.functionContext.addShedLocal(name); - - var context = new WasmCodeGenContext(moduleContext, result.context); - - context = setLocal.apply(context.shedLocal(name), context); - - for (var func : result.value) { - context = func.apply(context); - } - - return context; - } - - public WasmCodeGenContext onceShedLocalDefined(String name, Function func) { - var local = this.functionContext.shedLocalOrNone(name); - - if (local.isEmpty()) { - return new WasmCodeGenContext( - this.moduleContext, - this.functionContext.addWaitingForShedLocal(name, func) - ); - } else { - return func.apply(this); - } - } - - public WasmLocalIndex shedLocal(String name) { - return functionContext.shedLocal(name); - } - - public WasmCodeGenResult generateLocal(WasmCodeGenLocalSpace space) { - var result = functionContext.generateLocal(space, Optional.empty()); - - return new WasmCodeGenContext(this.moduleContext, result.context).toResult(result.value); - } - - public WasmCodeGenResult generateLocal(WasmCodeGenLocalSpace space, String name) { - var result = functionContext.generateLocal(space, Optional.of(name)); - - return new WasmCodeGenContext(this.moduleContext, result.context).toResult(result.value); - } - - public WasmTableIndex indirectFunctionTableIndex() { - return new WasmTableIndex(0); - } - - public WasmCodeGenContext createFunction( - String name, - WasmFuncType funcType, - Function create - ) { - var bodyContext = new WasmCodeGenContext( - this.moduleContext, - FunctionContext.forFuncType(funcType) - ); - - bodyContext = create.apply(bodyContext); - - var function = bodyContext.functionContext.toFunction(name); - - return new WasmCodeGenContext( - bodyContext.moduleContext.addFunction(function), - this.functionContext - ); - } - - public WasmCodeGenResult toResult(T value) { - return new WasmCodeGenResult<>(value, this); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenGlobalSpace.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenGlobalSpace.java deleted file mode 100644 index 18c265e2..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenGlobalSpace.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -public enum WasmCodeGenGlobalSpace { - FUNCTION("function"), - DATA_NAMESPACE("namespace"), - DATA_STRING("string"); - - private final String name; - - WasmCodeGenGlobalSpace(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenLocalSpace.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenLocalSpace.java deleted file mode 100644 index 534cc6fc..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenLocalSpace.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -public enum WasmCodeGenLocalSpace { - CALL_ARG_POSITIONAL("callArgPositional"), - CALL_ARG_NAMED("callArgNamed"), - CLOSURE_POINTER("closurePointer"), - CLOSURE_FREE_VARIABLE("closureFreeVariable"), - FIELD_VALUE("fieldValue"), - LOCAL("local"), - MAIN("main"), - NAMESPACE("namespace"), - PARAM("param"), - RECEIVER("receiver"); - - private final String name; - - WasmCodeGenLocalSpace(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenNamespaces.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenNamespaces.java deleted file mode 100644 index f951d644..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenNamespaces.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -import org.shedlang.compiler.backends.wasm.structure.ast.instructions.*; -import org.shedlang.compiler.backends.wasm.structure.ast.linking.WasmMemoryAddress; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.*; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmFuncType; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmGlobalType; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmMutability; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmValueType; -import org.shedlang.compiler.types.NamespaceName; - -import java.util.List; -import java.util.function.Function; - -public class WasmCodeGenNamespaces { - private WasmCodeGenNamespaces() { - } - - public static WasmCodeGenContext importValue( - NamespaceName namespaceName, - WasmCodeGenContext context - ) { - var importFuncName = new WasmFuncName(globalNameNamespaceImport(namespaceName)); - return context - .addImport(new WasmImport( - "env", - importFuncName.value(), - new WasmImportDescriptor.Func( - importFuncName.value(), - new WasmFuncType(List.of(), List.of(WasmCodeGenTypes.VALUE_TYPE)) - ) - )) - .addInstruction(new WasmCall(importFuncName)); - } - - public static WasmCodeGenContext define( - NamespaceName namespaceName, - Function generateInitBody, - WasmCodeGenContext context - ) { - var namespaceTypeInfo = context.typeInfo().namespaceTypeInfo(namespaceName); - - context = context.addData( - globalNameNamespaceValue(namespaceName), - // TODO: remove magic number - new byte[4 * namespaceTypeInfo.fieldCount()], - WasmAlignment.ALIGN_32_BIT - ).context(); - - context = context.createFunction( - globalNameNamespaceInit(namespaceName), - new WasmFuncType(List.of(), List.of()), - initContext -> { - initContext = generateInitBody.apply(initContext); - - initContext = initContext - .addInstruction(new WasmI32Const(1)) - .addInstruction(new WasmGlobalSet( - new WasmGlobalName(globalNameNamespaceIsInited(namespaceName)) - )); - - return initContext; - } - ); - - context = context.addGlobal(new WasmGlobal( - globalNameNamespaceIsInited(namespaceName), - new WasmGlobalType(WasmValueType.I32, WasmMutability.MUTABLE), - new WasmExpression(List.of(new WasmI32Const(0))) - )); - - context = context.createFunction( - globalNameNamespaceImport(namespaceName), - new WasmFuncType(List.of(), List.of(WasmCodeGenTypes.VALUE_TYPE)), - bodyContext -> { - return bodyContext - .addInstruction(new WasmGlobalGet( - new WasmGlobalName(globalNameNamespaceIsInited(namespaceName)) - )) - .addInstruction(new WasmIf( - new WasmBlockType(List.of()), - List.of(), - List.of( - new WasmCall(new WasmFuncName(globalNameNamespaceInit(namespaceName))), - new WasmI32Const(1), - new WasmGlobalSet(new WasmGlobalName(globalNameNamespaceIsInited(namespaceName))) - ) - )) - .addInstruction(new WasmMemoryAddressConst(namespaceMemoryAddress(namespaceName))); - } - ); - - return context; - } - - public static WasmCodeGenContext fieldStore( - NamespaceName namespaceName, - String fieldName, - WasmLocalIndex fieldValue, - WasmCodeGenContext context - ) { - var namespaceAddress = namespaceMemoryAddress(namespaceName); - - return context - .addInstruction(new WasmMemoryAddressConst(namespaceAddress)) - .addInstruction(new WasmLocalGet(fieldValue)) - .addInstruction(new WasmI32Store(fieldMemoryArg( - namespaceName, - fieldName, - context - ))); - } - - public static WasmCodeGenContext fieldLoad( - NamespaceName namespaceName, - WasmLocalIndex namespace, - String fieldName, - WasmCodeGenContext context - ) { - return context - .addInstruction(new WasmLocalGet(namespace)) - .addInstruction(new WasmI32Load(fieldMemoryArg( - namespaceName, - fieldName, - context - ))); - } - - private static WasmMemoryAddress namespaceMemoryAddress(NamespaceName namespaceName) { - var dataName = globalNameNamespaceValue(namespaceName); - return new WasmMemoryAddress(dataName); - } - - private static WasmMemoryArg fieldMemoryArg( - NamespaceName namespaceName, - String fieldName, - WasmCodeGenContext context - ) { - var namespaceTypeInfo = context.typeInfo().namespaceTypeInfo(namespaceName); - - return new WasmMemoryArg( - // TODO: remove magic number - namespaceTypeInfo.fieldIndex(fieldName) * 4, - WasmAlignment.ALIGN_32_BIT - ); - } - - 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 globalNameNamespaceIsInited(NamespaceName namespaceName) { - return "shed__namespaceIsInited__" + namespaceNameToWasmIdentifier(namespaceName); - } - - private static String globalNameNamespaceImport(NamespaceName namespaceName) { - return "shed__namespaceImport__" + namespaceNameToWasmIdentifier(namespaceName); - } - - public static String namespaceNameToWasmIdentifier(NamespaceName namespaceName) { - return String.join("_", namespaceName.parts()); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenResult.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenResult.java deleted file mode 100644 index c20e8409..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenResult.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -public record WasmCodeGenResult(T value, WasmCodeGenContext context) { -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java deleted file mode 100644 index d596c53c..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenStrings.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -import org.shedlang.compiler.backends.wasm.structure.ast.instructions.WasmCall; -import org.shedlang.compiler.backends.wasm.structure.ast.linking.WasmMemoryAddress; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmAlignment; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmFuncName; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmImport; -import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmImportDescriptor; -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmFuncType; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; -import java.util.List; - -public class WasmCodeGenStrings { - private WasmCodeGenStrings() { - } - - public static WasmCodeGenResult defineString( - String value, - WasmCodeGenContext context - ) { - var codeUnits = value.getBytes(StandardCharsets.UTF_8); - var data = ByteBuffer.allocate(4 + codeUnits.length); - data.order(ByteOrder.LITTLE_ENDIAN); - data.putInt(codeUnits.length); - data.put(codeUnits); - - return context.addData( - context.generateGlobalName(WasmCodeGenGlobalSpace.DATA_STRING), - data.array(), - WasmAlignment.ALIGN_32_BIT - ); - } - - public static WasmCodeGenContext add(WasmCodeGenContext context) { - var runtimeAddName = "shed__runtime__string_add"; - - return context - .addImport(new WasmImport( - "env", - runtimeAddName, - new WasmImportDescriptor.Func( - runtimeAddName, - new WasmFuncType( - List.of(WasmCodeGenTypes.STRING_TYPE, WasmCodeGenTypes.STRING_TYPE), - List.of(WasmCodeGenTypes.STRING_TYPE) - ) - ) - )) - .addInstruction(new WasmCall(new WasmFuncName(runtimeAddName))); - } -} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenTypes.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenTypes.java deleted file mode 100644 index 27010de9..00000000 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGenTypes.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.shedlang.compiler.backends.wasm; - -import org.shedlang.compiler.backends.wasm.structure.ast.types.WasmValueType; - -public class WasmCodeGenTypes { - private WasmCodeGenTypes() { - } - - public static final WasmValueType VALUE_TYPE = WasmValueType.I32; - public static final WasmValueType STRING_TYPE = VALUE_TYPE; -} -- cgit v1.2.3