Search in sources :

Example 6 with Program

use of de.mirkosertic.bytecoder.ssa.Program in project Bytecoder by mirkosertic.

the class OpenCLCompileBackend method generateCodeFor.

@Override
public OpenCLCompileResult generateCodeFor(CompileOptions aOptions, BytecodeLinkerContext aLinkerContext, Class aEntryPointClass, String aEntryPointMethodName, BytecodeMethodSignature aEntryPointSignatue) {
    BytecodeLinkerContext theLinkerContext = new BytecodeLinkerContext(loader, aOptions.getLogger());
    BytecodeLinkedClass theKernelClass = theLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(aEntryPointClass));
    theKernelClass.resolveVirtualMethod(aEntryPointMethodName, aEntryPointSignatue);
    BytecodeResolvedMethods theMethodMap = theKernelClass.resolvedMethods();
    StringWriter theStrWriter = new StringWriter();
    OpenCLInputOutputs theInputOutputs;
    // First of all, we link the kernel method
    BytecodeMethod theKernelMethod = theKernelClass.getBytecodeClass().methodByNameAndSignatureOrNull("processWorkItem", new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[0]));
    ProgramGenerator theGenerator = programGeneratorFactory.createFor(aLinkerContext);
    Program theSSAProgram = theGenerator.generateFrom(theKernelClass.getBytecodeClass(), theKernelMethod);
    // Run optimizer
    aOptions.getOptimizer().optimize(theSSAProgram.getControlFlowGraph(), aLinkerContext);
    // Every member of the kernel class becomes a kernel function argument
    try {
        theInputOutputs = inputOutputsFor(theLinkerContext, theKernelClass, theSSAProgram);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    // And then we ca pass it to the code generator to generate the kernel code
    OpenCLWriter theSSAWriter = new OpenCLWriter(theKernelClass, aOptions, theSSAProgram, "", new PrintWriter(theStrWriter), aLinkerContext, theInputOutputs);
    // We use the relooper here
    Relooper theRelooper = new Relooper();
    theMethodMap.stream().forEach(aMethodMapEntry -> {
        BytecodeMethod theMethod = aMethodMapEntry.getValue();
        if (theMethod.isConstructor()) {
            return;
        }
        if (theMethod != theKernelMethod) {
            Program theSSAProgram1 = theGenerator.generateFrom(aMethodMapEntry.getProvidingClass().getBytecodeClass(), theMethod);
            // Run optimizer
            aOptions.getOptimizer().optimize(theSSAProgram1.getControlFlowGraph(), aLinkerContext);
            // Try to reloop it!
            try {
                Relooper.Block theReloopedBlock = theRelooper.reloop(theSSAProgram1.getControlFlowGraph());
                theSSAWriter.printReloopedInline(theMethod, theSSAProgram1, theReloopedBlock);
            } catch (Exception e) {
                throw new IllegalStateException("Error relooping cfg", e);
            }
        }
    });
    // Finally, we write the kernel method
    try {
        Relooper.Block theReloopedBlock = theRelooper.reloop(theSSAProgram.getControlFlowGraph());
        theSSAWriter.printReloopedKernel(theSSAProgram, theReloopedBlock);
    } catch (Exception e) {
        throw new IllegalStateException("Error relooping cfg", e);
    }
    return new OpenCLCompileResult(theInputOutputs, theStrWriter.toString());
}
Also used : Program(de.mirkosertic.bytecoder.ssa.Program) BytecodeMethodSignature(de.mirkosertic.bytecoder.core.BytecodeMethodSignature) BytecodeMethod(de.mirkosertic.bytecoder.core.BytecodeMethod) NaiveProgramGenerator(de.mirkosertic.bytecoder.ssa.NaiveProgramGenerator) ProgramGenerator(de.mirkosertic.bytecoder.ssa.ProgramGenerator) BytecodeTypeRef(de.mirkosertic.bytecoder.core.BytecodeTypeRef) BytecodeResolvedMethods(de.mirkosertic.bytecoder.core.BytecodeResolvedMethods) StringWriter(java.io.StringWriter) Relooper(de.mirkosertic.bytecoder.relooper.Relooper) BytecodeLinkerContext(de.mirkosertic.bytecoder.core.BytecodeLinkerContext) BytecodeLinkedClass(de.mirkosertic.bytecoder.core.BytecodeLinkedClass) PrintWriter(java.io.PrintWriter)

Example 7 with Program

use of de.mirkosertic.bytecoder.ssa.Program in project Bytecoder by mirkosertic.

the class RedundantAssignmentOptimizerTest method testBinaryOptimization.

@Test
public void testBinaryOptimization() {
    Program theProgram = new Program();
    ControlFlowGraph theGraph = new ControlFlowGraph(theProgram);
    RegionNode theStart = theGraph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
    ExpressionList theExpressions = theStart.getExpressions();
    Variable theVariable1 = new Variable(TypeRef.Native.INT, "var1");
    Variable theVariable2 = new Variable(TypeRef.Native.INT, "var2");
    IntegerValue theInt1 = new IntegerValue(10);
    theVariable1.initializeWith(theInt1);
    theExpressions.add(new VariableAssignmentExpression(theVariable1, theInt1));
    IntegerValue theInt2 = new IntegerValue(20);
    theVariable2.initializeWith(theInt2);
    theExpressions.add(new VariableAssignmentExpression(theVariable2, theInt2));
    Variable theVariable3 = new Variable(TypeRef.Native.INT, "var3");
    BinaryExpression theBinary = new BinaryExpression(TypeRef.Native.INT, theVariable1, BinaryExpression.Operator.ADD, theVariable2);
    theVariable3.initializeWith(theBinary);
    theExpressions.add(new VariableAssignmentExpression(theVariable3, theBinary));
    theExpressions.add(new ReturnValueExpression(theVariable3));
    RedundantAssignmentOptimizer theOptimizer = new RedundantAssignmentOptimizer();
    theOptimizer.optimize(theGraph, null);
    System.out.println(theExpressions);
}
Also used : ReturnValueExpression(de.mirkosertic.bytecoder.ssa.ReturnValueExpression) Program(de.mirkosertic.bytecoder.ssa.Program) Variable(de.mirkosertic.bytecoder.ssa.Variable) BinaryExpression(de.mirkosertic.bytecoder.ssa.BinaryExpression) ControlFlowGraph(de.mirkosertic.bytecoder.ssa.ControlFlowGraph) IntegerValue(de.mirkosertic.bytecoder.ssa.IntegerValue) RegionNode(de.mirkosertic.bytecoder.ssa.RegionNode) ExpressionList(de.mirkosertic.bytecoder.ssa.ExpressionList) VariableAssignmentExpression(de.mirkosertic.bytecoder.ssa.VariableAssignmentExpression) Test(org.junit.Test)

Example 8 with Program

use of de.mirkosertic.bytecoder.ssa.Program in project Bytecoder by mirkosertic.

the class OpenCLWriter method printReloopedInline.

public void printReloopedInline(BytecodeMethod aMethod, Program aProgram, Relooper.Block aBlock) {
    BytecodeMethodSignature theSignature = aMethod.getSignature();
    print("__inline ");
    print(toType(TypeRef.toType(theSignature.getReturnType())));
    print(" ");
    print(aMethod.getName().stringValue());
    print("(");
    boolean theFirst = true;
    List<OpenCLInputOutputs.KernelArgument> theArguments = inputOutputs.arguments();
    for (OpenCLInputOutputs.KernelArgument theArgument1 : theArguments) {
        if (theFirst) {
            theFirst = false;
        } else {
            print(", ");
        }
        TypeRef theTypeRef = TypeRef.toType(theArgument1.getField().getValue().getTypeRef());
        switch(theArgument1.getType()) {
            case INPUT:
                print("const ");
                print(toType(theTypeRef));
                print(" ");
                print(theArgument1.getField().getValue().getName().stringValue());
                break;
            case OUTPUT:
            case INPUTOUTPUT:
                print(toType(theTypeRef));
                print(" ");
                print(theArgument1.getField().getValue().getName().stringValue());
                break;
        }
    }
    List<Program.Argument> theProgramArguments = aProgram.getArguments();
    for (int i = 1; i < theProgramArguments.size(); i++) {
        Program.Argument theArgument = theProgramArguments.get(i);
        if (theFirst) {
            theFirst = false;
        } else {
            print(", ");
        }
        print(toType(theArgument.getVariable().resolveType()));
        print(" ");
        print(theArgument.getVariable().getName());
    }
    println(") {");
    OpenCLWriter theDeeper = withDeeperIndent();
    theDeeper.println("int $__label__ = 0;");
    for (Variable theVariable : aProgram.getVariables()) {
        if (!theVariable.isSynthetic()) {
            theDeeper.print(toType(theVariable.resolveType(), false));
            theDeeper.print(" ");
            theDeeper.print(theVariable.getName());
            theDeeper.println(";");
        }
    }
    theDeeper.print(aBlock);
    println("}");
}
Also used : Program(de.mirkosertic.bytecoder.ssa.Program) Variable(de.mirkosertic.bytecoder.ssa.Variable) BytecodeMethodSignature(de.mirkosertic.bytecoder.core.BytecodeMethodSignature) TypeRef(de.mirkosertic.bytecoder.ssa.TypeRef) BytecodeObjectTypeRef(de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef)

Example 9 with Program

use of de.mirkosertic.bytecoder.ssa.Program in project Bytecoder by mirkosertic.

the class WASMSSACompilerBackend method generateCodeFor.

@Override
public WASMCompileResult generateCodeFor(CompileOptions aOptions, BytecodeLinkerContext aLinkerContext, Class aEntryPointClass, String aEntryPointMethodName, BytecodeMethodSignature aEntryPointSignatue) {
    // Link required mamory management code
    BytecodeLinkedClass theArrayClass = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(Array.class));
    BytecodeLinkedClass theManagerClass = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(MemoryManager.class));
    theManagerClass.resolveStaticMethod("freeMem", new BytecodeMethodSignature(BytecodePrimitiveTypeRef.LONG, new BytecodeTypeRef[0]));
    theManagerClass.resolveStaticMethod("usedMem", new BytecodeMethodSignature(BytecodePrimitiveTypeRef.LONG, new BytecodeTypeRef[0]));
    theManagerClass.resolveStaticMethod("free", new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[] { BytecodeObjectTypeRef.fromRuntimeClass(Address.class) }));
    theManagerClass.resolveStaticMethod("malloc", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT }));
    theManagerClass.resolveStaticMethod("newObject", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
    theManagerClass.resolveStaticMethod("newArray", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
    theManagerClass.resolveStaticMethod("newArray", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
    BytecodeLinkedClass theStringClass = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(String.class));
    if (!theStringClass.resolveConstructorInvocation(new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[] { new BytecodeArrayTypeRef(BytecodePrimitiveTypeRef.BYTE, 1) }))) {
        throw new IllegalStateException("No matching constructor!");
    }
    StringWriter theStringWriter = new StringWriter();
    PrintWriter theWriter = new PrintWriter(theStringWriter);
    theWriter.println("(module");
    theWriter.println("   (func $float_remainder (import \"math\" \"float_rem\") (param $p1 f32) (param $p2 f32) (result f32))\n");
    // Print imported functions first
    aLinkerContext.linkedClasses().forEach(aEntry -> {
        if (aEntry.targetNode().getBytecodeClass().getAccessFlags().isInterface()) {
            return;
        }
        if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
            return;
        }
        BytecodeResolvedMethods theMethodMap = aEntry.targetNode().resolvedMethods();
        theMethodMap.stream().forEach(aMethodMapEntry -> {
            // Only add implementation methods
            if (!(aMethodMapEntry.getProvidingClass() == aEntry.targetNode())) {
                return;
            }
            BytecodeMethod t = aMethodMapEntry.getValue();
            BytecodeMethodSignature theSignature = t.getSignature();
            if (t.getAccessFlags().isNative()) {
                if (aMethodMapEntry.getProvidingClass().getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
                    return;
                }
                BytecodeImportedLink theLink = aMethodMapEntry.getProvidingClass().linkfor(t);
                // Imported function
                theWriter.print("   (func ");
                theWriter.print("$");
                theWriter.print(WASMWriterUtils.toMethodName(aMethodMapEntry.getProvidingClass().getClassName(), t.getName(), theSignature));
                theWriter.print(" (import \"");
                theWriter.print(theLink.getModuleName());
                theWriter.print("\" \"");
                theWriter.print(theLink.getLinkName());
                theWriter.print("\") ");
                theWriter.print("(param $thisRef");
                theWriter.print(" ");
                theWriter.print(WASMWriterUtils.toType(TypeRef.Native.REFERENCE));
                theWriter.print(") ");
                for (int i = 0; i < theSignature.getArguments().length; i++) {
                    BytecodeTypeRef theParamType = theSignature.getArguments()[i];
                    theWriter.print("(param $p");
                    theWriter.print((i + 1));
                    theWriter.print(" ");
                    theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theParamType)));
                    theWriter.print(") ");
                }
                if (!theSignature.getReturnType().isVoid()) {
                    // result
                    theWriter.print("(result ");
                    theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theSignature.getReturnType())));
                    theWriter.print(")");
                }
                theWriter.println(")");
            }
        });
    });
    Map<String, String> theGlobalTypes = new HashMap<>();
    theGlobalTypes.put("RESOLVEMETHOD", "(func (param i32) (param i32) (result i32))");
    theGlobalTypes.put("INSTANCEOF", "(func (param i32) (param i32) (result i32))");
    theWriter.println();
    List<String> theGeneratedFunctions = new ArrayList<>();
    theGeneratedFunctions.add("LAMBDA__resolvevtableindex");
    theGeneratedFunctions.add("RUNTIMECLASS__resolvevtableindex");
    theGeneratedFunctions.add("jlClass_A1jlObjectgetEnumConstants");
    theGeneratedFunctions.add("jlClass_BOOLEANdesiredAssertionStatus");
    List<BytecodeLinkedClass> theLinkedClasses = new ArrayList<>();
    ConstantPool theConstantPool = new ConstantPool();
    Map<String, CallSite> theCallsites = new HashMap<>();
    WASMSSAWriter.IDResolver theResolver = new WASMSSAWriter.IDResolver() {

        @Override
        public int resolveVTableMethodByType(BytecodeObjectTypeRef aObjectType) {
            String theClassName = WASMWriterUtils.toClassName(aObjectType);
            String theMethodName = theClassName + "__resolvevtableindex";
            int theIndex = theGeneratedFunctions.indexOf(theMethodName);
            if (theIndex < 0) {
                throw new IllegalStateException("Cannot resolve vtable method for " + theClassName);
            }
            return theIndex;
        }

        @Override
        public String resolveStringPoolFunctionName(StringValue aValue) {
            return "stringPool" + theConstantPool.register(aValue);
        }

        @Override
        public String resolveCallsiteBootstrapFor(BytecodeClass aOwningClass, String aCallsiteId, Program aProgram, RegionNode aBootstrapMethod) {
            String theID = "callsite_" + aCallsiteId.replace("/", "_");
            CallSite theCallsite = theCallsites.computeIfAbsent(theID, k -> new CallSite(aProgram, aBootstrapMethod));
            return theID;
        }

        @Override
        public int resolveMethodIDByName(String aMethodName) {
            int theIndex = theGeneratedFunctions.indexOf(aMethodName);
            if (theIndex < 0) {
                throw new IllegalStateException("Cannot resolve method " + aMethodName);
            }
            return theIndex;
        }

        @Override
        public void registerGlobalType(BytecodeMethodSignature aSignature, boolean aStatic) {
            String theMethodSignature = WASMWriterUtils.toMethodSignature(aSignature, aStatic);
            if (!theGlobalTypes.containsKey(theMethodSignature)) {
                String theTypeDefinition = WASMWriterUtils.toWASMMethodSignature(aSignature);
                theGlobalTypes.put(theMethodSignature, theTypeDefinition);
            }
        }
    };
    aLinkerContext.linkedClasses().forEach(aEntry -> {
        if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
            return;
        }
        theLinkedClasses.add(aEntry.targetNode());
        String theClassName = WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef());
        if (!aEntry.targetNode().getBytecodeClass().getAccessFlags().isInterface()) {
            theGeneratedFunctions.add(theClassName + "__resolvevtableindex");
            theGeneratedFunctions.add(theClassName + "__instanceof");
        }
        BytecodeResolvedMethods theMethodMap = aEntry.targetNode().resolvedMethods();
        theMethodMap.stream().forEach(aMapEntry -> {
            BytecodeMethod t = aMapEntry.getValue();
            // If the method is provided by the runtime, we do not need to generate the implementation
            if (t.getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
                return;
            }
            // Do not generate code for abstract methods
            if (t.getAccessFlags().isAbstract()) {
                return;
            }
            // Constructors for the same reason
            if (t.isConstructor()) {
                return;
            }
            // Class initializer also
            if (t.isClassInitializer()) {
                return;
            }
            // Only write real methods
            if (!(aMapEntry.getProvidingClass() == aEntry.targetNode())) {
                return;
            }
            BytecodeMethodSignature theSignature = t.getSignature();
            theResolver.registerGlobalType(theSignature, t.getAccessFlags().isStatic());
            if (aEntry.targetNode().getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
                return;
            }
            String theMethodName = WASMWriterUtils.toMethodName(aEntry.edgeType().objectTypeRef(), t.getName(), theSignature);
            if (!theGeneratedFunctions.contains(theMethodName)) {
                theGeneratedFunctions.add(theMethodName);
            }
        });
    });
    theWriter.println("   (memory (export \"memory\") 512 512)");
    // Write virtual method table
    if (!theGeneratedFunctions.isEmpty()) {
        theWriter.println();
        theWriter.print("   (table ");
        theWriter.print(theGeneratedFunctions.size());
        theWriter.println(" anyfunc)");
        for (int i = 0; i < theGeneratedFunctions.size(); i++) {
            theWriter.print("   (elem (i32.const ");
            theWriter.print(i);
            theWriter.print(") $");
            theWriter.print(theGeneratedFunctions.get(i));
            theWriter.println(")");
        }
        theWriter.println();
    }
    // Initialize memory layout for classes and instances
    WASMMemoryLayouter theMemoryLayout = new WASMMemoryLayouter(aLinkerContext);
    // Now everything else
    aLinkerContext.linkedClasses().forEach(aEntry -> {
        BytecodeLinkedClass theLinkedClass = aEntry.targetNode();
        if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
            return;
        }
        if (theLinkedClass.getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
            return;
        }
        Set<BytecodeObjectTypeRef> theStaticReferences = new HashSet<>();
        BytecodeResolvedMethods theMethodMap = theLinkedClass.resolvedMethods();
        theMethodMap.stream().forEach(aMethodMapEntry -> {
            BytecodeMethod theMethod = aMethodMapEntry.getValue();
            BytecodeMethodSignature theSignature = theMethod.getSignature();
            // If the method is provided by the runtime, we do not need to generate the implementation
            if (theMethod.getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
                return;
            }
            // Do not generate code for abstract methods
            if (theMethod.getAccessFlags().isAbstract()) {
                return;
            }
            if (theMethod.getAccessFlags().isNative()) {
                // Already written
                return;
            }
            if (!(aMethodMapEntry.getProvidingClass() == theLinkedClass)) {
                // But include static methods, as they are inherited from the base classes
                if (aMethodMapEntry.getValue().getAccessFlags().isStatic() && !aMethodMapEntry.getValue().isClassInitializer()) {
                    // We need to create a delegate function here
                    if (!theMethodMap.isImplementedBy(aMethodMapEntry.getValue(), theLinkedClass)) {
                        theWriter.print("   (func ");
                        theWriter.print("$");
                        theWriter.print(WASMWriterUtils.toMethodName(theLinkedClass.getClassName(), theMethod.getName(), theSignature));
                        theWriter.print(" ");
                        theWriter.print("(param $UNUSED");
                        theWriter.print(" ");
                        theWriter.print(WASMWriterUtils.toType(TypeRef.Native.REFERENCE));
                        theWriter.print(") ");
                        StringBuilder theArguments = new StringBuilder();
                        theArguments.append("(get_local $UNUSED)");
                        for (int i = 0; i < theSignature.getArguments().length; i++) {
                            theWriter.print("(param $p");
                            theWriter.print(i);
                            theWriter.print(" ");
                            theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theSignature.getArguments()[i])));
                            theWriter.print(") ");
                            theArguments.append(" (get_local $p");
                            theArguments.append(i);
                            theArguments.append(")");
                        }
                        if (!theSignature.getReturnType().isVoid()) {
                            // result
                            theWriter.print("(result ");
                            theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theSignature.getReturnType())));
                            theWriter.print(")");
                        }
                        theWriter.println();
                        // Static methods will just delegate to the implementation in the class
                        theWriter.println();
                        if (!theSignature.getReturnType().isVoid()) {
                            theWriter.print("         (return ");
                            theWriter.print("(call $");
                            theWriter.print(WASMWriterUtils.toMethodName(aMethodMapEntry.getProvidingClass().getClassName(), theMethod.getName(), theSignature));
                            theWriter.print(" ");
                            theWriter.print(theArguments);
                            theWriter.println(")))");
                        } else {
                            theWriter.print("         (call $");
                            theWriter.print(WASMWriterUtils.toMethodName(aMethodMapEntry.getProvidingClass().getClassName(), theMethod.getName(), theSignature));
                            theWriter.print(" ");
                            theWriter.print(theArguments);
                            theWriter.println("))");
                        }
                    }
                }
                return;
            }
            ProgramGenerator theGenerator = programGeneratorFactory.createFor(aLinkerContext);
            Program theSSAProgram = theGenerator.generateFrom(aMethodMapEntry.getProvidingClass().getBytecodeClass(), theMethod);
            // Run optimizer
            aOptions.getOptimizer().optimize(theSSAProgram.getControlFlowGraph(), aLinkerContext);
            theWriter.print("   (func ");
            theWriter.print("$");
            theWriter.print(WASMWriterUtils.toMethodName(theLinkedClass.getClassName(), theMethod.getName(), theSignature));
            theWriter.print(" ");
            if (theMethod.getAccessFlags().isStatic()) {
                theWriter.print("(param $UNUSED");
                theWriter.print(" ");
                theWriter.print(WASMWriterUtils.toType(TypeRef.Native.REFERENCE));
                theWriter.print(") ");
            }
            for (Program.Argument theArgument : theSSAProgram.getArguments()) {
                Variable theVariable = theArgument.getVariable();
                theWriter.print("(param $");
                theWriter.print(theVariable.getName());
                theWriter.print(" ");
                theWriter.print(WASMWriterUtils.toType(theVariable.resolveType()));
                theWriter.print(") ");
            }
            if (!theSignature.getReturnType().isVoid()) {
                // result
                theWriter.print("(result ");
                theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theSignature.getReturnType())));
                theWriter.print(")");
            }
            theWriter.println();
            theStaticReferences.addAll(theSSAProgram.getStaticReferences());
            WASMSSAWriter theSSAWriter = new WASMSSAWriter(aOptions, theSSAProgram, "         ", theWriter, aLinkerContext, theResolver, theMemoryLayout);
            for (Variable theVariable : theSSAProgram.getVariables()) {
                if (!(theVariable.isSynthetic()) && !theSSAWriter.isStackVariable(theVariable)) {
                    theSSAWriter.print("(local $");
                    theSSAWriter.print(theVariable.getName());
                    theSSAWriter.print(" ");
                    theSSAWriter.print(WASMWriterUtils.toType(theVariable.resolveType()));
                    theSSAWriter.print(") ;; ");
                    theSSAWriter.println(theVariable.resolveType().resolve().name());
                }
            }
            // Try to reloop it!
            try {
                Relooper theRelooper = new Relooper();
                Relooper.Block theReloopedBlock = theRelooper.reloop(theSSAProgram.getControlFlowGraph());
                theSSAWriter.writeRelooped(theReloopedBlock);
            } catch (Exception e) {
                throw new IllegalStateException("Error relooping cfg", e);
            }
            theWriter.println("   )");
            theWriter.println();
        });
        String theClassName = WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef());
        if (!theLinkedClass.getBytecodeClass().getAccessFlags().isInterface()) {
            theWriter.print("   (func ");
            theWriter.print("$");
            theWriter.print(theClassName);
            theWriter.println("__resolvevtableindex (param $thisRef i32) (param $p1 i32) (result i32)");
            List<BytecodeResolvedMethods.MethodEntry> theEntries = theMethodMap.stream().collect(Collectors.toList());
            Set<BytecodeVirtualMethodIdentifier> theVisitedMethods = new HashSet<>();
            for (int i = theEntries.size() - 1; i >= 0; i--) {
                BytecodeResolvedMethods.MethodEntry aMethodMapEntry = theEntries.get(i);
                BytecodeMethod theMethod = aMethodMapEntry.getValue();
                if (!theMethod.getAccessFlags().isStatic() && !theMethod.getAccessFlags().isPrivate() && !theMethod.isConstructor() && !theMethod.getAccessFlags().isAbstract() && (theMethod != BytecodeLinkedClass.GET_CLASS_PLACEHOLDER)) {
                    BytecodeVirtualMethodIdentifier theMethodIdentifier = aLinkerContext.getMethodCollection().identifierFor(theMethod);
                    if (theVisitedMethods.add(theMethodIdentifier)) {
                        theWriter.println("         (block $b");
                        theWriter.print("             (br_if $b (i32.ne (get_local $p1) (i32.const ");
                        theWriter.print(theMethodIdentifier.getIdentifier());
                        theWriter.println(")))");
                        String theFullMethodName = WASMWriterUtils.toMethodName(aMethodMapEntry.getProvidingClass().getClassName(), theMethod.getName(), theMethod.getSignature());
                        int theIndex = theGeneratedFunctions.indexOf(theFullMethodName);
                        if (theIndex < 0) {
                            throw new IllegalStateException("Unknown index : " + theFullMethodName);
                        }
                        theWriter.print("             (return (i32.const ");
                        theWriter.print(theIndex);
                        theWriter.println("))");
                        theWriter.println("         )");
                    }
                }
            }
            ;
            theWriter.println("         (block $b");
            theWriter.print("             (br_if $b (i32.ne (get_local $p1) (i32.const ");
            theWriter.print(WASMSSAWriter.GENERATED_INSTANCEOF_METHOD_ID);
            theWriter.println(")))");
            String theFullMethodName = theClassName + "__instanceof";
            int theIndex = theGeneratedFunctions.indexOf(theFullMethodName);
            if (theIndex < 0) {
                throw new IllegalStateException("Unknown index : " + theFullMethodName);
            }
            theWriter.print("             (return (i32.const ");
            theWriter.print(theIndex);
            theWriter.println("))");
            theWriter.println("         )");
            theWriter.println("         (unreachable)");
            theWriter.println("   )");
            theWriter.println();
            // Instanceof method
            theWriter.print("   (func ");
            theWriter.print("$");
            theWriter.print(theClassName);
            theWriter.println("__instanceof (param $thisRef i32) (param $p1 i32) (result i32)");
            for (BytecodeLinkedClass theType : theLinkedClass.getImplementingTypes()) {
                theWriter.print("         (block $block");
                theWriter.print(theType.getUniqueId());
                theWriter.println();
                theWriter.print("             (br_if $block");
                theWriter.print(theType.getUniqueId());
                theWriter.print(" (i32.ne (get_local $p1) (i32.const ");
                theWriter.print(theType.getUniqueId());
                theWriter.println(")))");
                theWriter.println("             (return (i32.const 1))");
                theWriter.println("         )");
            }
            theWriter.println("         (return (i32.const 0))");
            theWriter.println("   )");
            theWriter.println();
        }
        theWriter.print("   (func ");
        theWriter.print("$");
        theWriter.print(theClassName);
        theWriter.println("__classinitcheck");
        theWriter.println("      (block $check");
        theWriter.print("         (br_if $check (i32.eq (i32.load offset=8 (get_global $");
        theWriter.print(theClassName);
        theWriter.println("__runtimeClass)) (i32.const 1)))");
        theWriter.print("         (i32.store offset=8 (get_global $");
        theWriter.print(theClassName);
        theWriter.println("__runtimeClass) (i32.const 1))");
        for (BytecodeObjectTypeRef theRef : theStaticReferences) {
            if (!Objects.equals(theRef, aEntry.edgeType().objectTypeRef())) {
                theWriter.print("         (call $");
                theWriter.print(WASMWriterUtils.toClassName(theRef));
                theWriter.println("__classinitcheck)");
            }
        }
        if (theLinkedClass.hasClassInitializer()) {
            theWriter.print("         (call $");
            theWriter.print(theClassName);
            theWriter.println("_VOIDclinit (i32.const 0))");
        }
        theWriter.println("      )");
        theWriter.println("   )");
        theWriter.println();
    });
    // Render callsites
    for (Map.Entry<String, CallSite> theEntry : theCallsites.entrySet()) {
        theWriter.print("   (func ");
        theWriter.print("$");
        theWriter.print(theEntry.getKey());
        theWriter.print(" ");
        // result
        theWriter.print("(result ");
        theWriter.print(WASMWriterUtils.toType(TypeRef.Native.REFERENCE));
        theWriter.print(")");
        theWriter.println();
        Program theSSAProgram = theEntry.getValue().program;
        WASMSSAWriter theSSAWriter = new WASMSSAWriter(aOptions, theSSAProgram, "         ", theWriter, aLinkerContext, theResolver, theMemoryLayout);
        for (Variable theVariable : theSSAProgram.getVariables()) {
            if (!(theVariable.isSynthetic()) && !(theSSAWriter.isStackVariable(theVariable))) {
                theSSAWriter.print("(local $");
                theSSAWriter.print(theVariable.getName());
                theSSAWriter.print(" ");
                theSSAWriter.print(WASMWriterUtils.toType(theVariable.resolveType()));
                theSSAWriter.print(") ;; ");
                theSSAWriter.println(theVariable.resolveType().resolve().name());
            }
        }
        theSSAWriter.printStackEnter();
        theSSAWriter.writeExpressionList(theEntry.getValue().bootstrapMethod.getExpressions());
        theWriter.println("   )");
        theWriter.println();
    }
    theWriter.println("   (func $newRuntimeClass (param $type i32) (param $staticSize i32) (param $enumValuesOffset i32) (result i32)");
    theWriter.println("         (local $newRef i32)");
    theWriter.println("         (set_local $newRef");
    theWriter.print("              (call $");
    theWriter.print(WASMWriterUtils.toClassName(theManagerClass.getClassName()));
    theWriter.print("_dmbcAddressnewObjectINTINTINT (i32.const 0) (get_local $staticSize) (i32.const -1) (i32.const ");
    theWriter.print(theGeneratedFunctions.indexOf("RUNTIMECLASS__resolvevtableindex"));
    theWriter.println("))");
    theWriter.println("         )");
    theWriter.println("         (i32.store offset=12 (get_local $newRef) (i32.add (get_local $newRef) (get_local $enumValuesOffset)))");
    theWriter.println("         (return (get_local $newRef))");
    theWriter.println("   )");
    theWriter.println();
    theWriter.println("   (func $LAMBDA__resolvevtableindex (param $thisRef i32) (param $methodId i32) (result i32)");
    theWriter.println("         (return (i32.load offset=8 (get_local $thisRef)))");
    theWriter.println("   )");
    theWriter.println();
    int theLambdaVTableResolveIndex = theGeneratedFunctions.indexOf("LAMBDA__resolvevtableindex");
    if (theLambdaVTableResolveIndex < 0) {
        throw new IllegalStateException("Cannot resolve LAMBDA__resolvevtableindex");
    }
    theWriter.println("   (func $newLambda (param $type i32) (param $implMethodNumber i32) (result i32)");
    theWriter.println("         (local $newRef i32)");
    theWriter.println("         (set_local $newRef");
    theWriter.print("            (call $");
    theWriter.print(WASMWriterUtils.toClassName(theManagerClass.getClassName()));
    theWriter.print("_dmbcAddressnewObjectINTINTINT (i32.const 0) (i32.const 12) (get_local $type) (i32.const ");
    theWriter.print(theLambdaVTableResolveIndex);
    theWriter.println("))");
    theWriter.println("         )");
    theWriter.println("         (i32.store offset=8 (get_local $newRef) (get_local $implMethodNumber))");
    theWriter.println("         (return (get_local $newRef))");
    theWriter.println("   )");
    theWriter.println();
    theWriter.println("   (func $compareValueI32 (param $p1 i32) (param $p2 i32) (result i32)");
    theWriter.println("     (block $b1");
    theWriter.println("         (br_if $b1");
    theWriter.println("             (i32.ne (get_local $p1) (get_local $p2))");
    theWriter.println("         )");
    theWriter.println("         (return (i32.const 0))");
    theWriter.println("     )");
    theWriter.println("     (block $b2");
    theWriter.println("         (br_if $b2");
    theWriter.println("             (i32.ge_s (get_local $p1) (get_local $p2))");
    theWriter.println("         )");
    theWriter.println("         (return (i32.const -1))");
    theWriter.println("     )");
    theWriter.println("     (return (i32.const 1))");
    theWriter.println("   )");
    theWriter.println();
    theWriter.println("   (func $compareValueF32 (param $p1 f32) (param $p2 f32) (result i32)");
    theWriter.println("     (block $b1");
    theWriter.println("         (br_if $b1");
    theWriter.println("             (f32.ne (get_local $p1) (get_local $p2))");
    theWriter.println("         )");
    theWriter.println("         (return (i32.const 0))");
    theWriter.println("     )");
    theWriter.println("     (block $b2");
    theWriter.println("         (br_if $b2");
    theWriter.println("             (f32.ge (get_local $p1) (get_local $p2))");
    theWriter.println("         )");
    theWriter.println("         (return (i32.const -1))");
    theWriter.println("     )");
    theWriter.println("     (return (i32.const 1))");
    theWriter.println("   )");
    theWriter.println();
    theWriter.println("   (func $INSTANCEOF_CHECK (param $thisRef i32) (param $type i32) (result i32)");
    theWriter.println("     (block $nullcheck");
    theWriter.println("         (br_if $nullcheck");
    theWriter.println("             (i32.ne (get_local $thisRef) (i32.const 0))");
    theWriter.println("         )");
    theWriter.println("         (return (i32.const 0))");
    theWriter.println("     )");
    theWriter.println("     (call_indirect $t_INSTANCEOF");
    theWriter.println("         (get_local $thisRef)");
    theWriter.println("         (get_local $type)");
    theWriter.println("         (call_indirect $t_RESOLVEMETHOD");
    theWriter.println("             (get_local $thisRef)");
    theWriter.print("             (i32.const ");
    theWriter.print(WASMSSAWriter.GENERATED_INSTANCEOF_METHOD_ID);
    theWriter.println(")");
    theWriter.println("             (i32.load offset=4 (get_local $thisRef))");
    theWriter.println("         )");
    theWriter.println("      )");
    theWriter.println("   )");
    theWriter.println();
    theWriter.println("   (func $jlClass_A1jlObjectgetEnumConstants (param $thisRef i32) (result i32)");
    theWriter.println("     (return (i32.load (i32.load offset=12 (get_local $thisRef))))");
    theWriter.println("   )");
    theWriter.println();
    theWriter.println("   (func $jlClass_BOOLEANdesiredAssertionStatus (param $thisRef i32) (result i32)");
    theWriter.println("     (return (i32.const 0))");
    theWriter.println("   )");
    theWriter.println();
    theWriter.println("   (func $RUNTIMECLASS__resolvevtableindex (param $thisRef i32) (param $methodId i32) (result i32)");
    BytecodeLinkedClass theClassLinkedCass = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(Class.class));
    BytecodeResolvedMethods theRuntimeMethodMap = theClassLinkedCass.resolvedMethods();
    theRuntimeMethodMap.stream().forEach(aMethodMapEntry -> {
        BytecodeMethod theMethod = aMethodMapEntry.getValue();
        if (!theMethod.getAccessFlags().isStatic()) {
            BytecodeVirtualMethodIdentifier theMethodIdentifier = aLinkerContext.getMethodCollection().identifierFor(theMethod);
            theWriter.println("     (block $m" + theMethodIdentifier.getIdentifier());
            theWriter.println("         (br_if $m" + theMethodIdentifier.getIdentifier() + " (i32.ne (get_local $methodId) (i32.const " + theMethodIdentifier.getIdentifier() + ")))");
            if (Objects.equals("getClass", theMethod.getName().stringValue())) {
                theWriter.println("         (unreachable)");
            } else if (Objects.equals("toString", theMethod.getName().stringValue())) {
                theWriter.println("         (unreachable)");
            } else if (Objects.equals("equals", theMethod.getName().stringValue())) {
                theWriter.println("         (unreachable)");
            } else if (Objects.equals("hashCode", theMethod.getName().stringValue())) {
                theWriter.println("         (unreachable)");
            } else if (Objects.equals("desiredAssertionStatus", theMethod.getName().stringValue())) {
                theWriter.println("         (return (i32.const " + theGeneratedFunctions.indexOf("Class_BOOLEANdesiredAssertionStatus") + "))");
            } else if (Objects.equals("getEnumConstants", theMethod.getName().stringValue())) {
                theWriter.println("         (return (i32.const " + theGeneratedFunctions.indexOf("Class_A1TObjectgetEnumConstants") + "))");
            } else {
                theWriter.println("         (unreachable)");
            }
            theWriter.println("     )");
        }
    });
    theWriter.println("     (unreachable)");
    theWriter.println("   )");
    theWriter.println();
    List<String> theGlobalVariables = new ArrayList<>();
    theWriter.println("   (func $bootstrap");
    theWriter.println("      (set_global $STACKTOP (i32.sub (i32.mul (current_memory) (i32.const 65536)) (i32.const 1)))");
    // Globals for static class data
    aLinkerContext.linkedClasses().forEach(aEntry -> {
        BytecodeLinkedClass theLinkedClass = aEntry.targetNode();
        if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
            return;
        }
        if (theLinkedClass.getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
            return;
        }
        theGlobalVariables.add(WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()) + "__runtimeClass");
        theWriter.print("      (set_global $");
        theWriter.print(WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
        theWriter.print("__runtimeClass (call $newRuntimeClass");
        theWriter.print(" (i32.const ");
        theWriter.print(theLinkedClass.getUniqueId());
        theWriter.print(")");
        WASMMemoryLayouter.MemoryLayout theLayout = theMemoryLayout.layoutFor(aEntry.edgeType().objectTypeRef());
        theWriter.print(" (i32.const ");
        theWriter.print(theLayout.classSize());
        theWriter.print(")");
        BytecodeResolvedFields theStaticFields = theLinkedClass.resolvedFields();
        if (theStaticFields.fieldByName("$VALUES") != null) {
            theWriter.print(" (i32.const ");
            theWriter.print(theLayout.offsetForClassMember("$VALUES"));
            theWriter.println(")");
        } else {
            theWriter.print(" (i32.const -1)");
        }
        theWriter.println("))");
    });
    WASMMemoryLayouter.MemoryLayout theStringMemoryLayout = theMemoryLayout.layoutFor(theStringClass.getClassName());
    aLinkerContext.linkedClasses().forEach(aEntry -> {
        if (aEntry.targetNode().getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
            return;
        }
        if (!Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
            theWriter.print("      (call $");
            theWriter.print(WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
            theWriter.println("__classinitcheck)");
        }
    });
    List<StringValue> thePoolValues = theConstantPool.stringValues();
    for (int i = 0; i < thePoolValues.size(); i++) {
        StringValue theConstantInPool = thePoolValues.get(i);
        String theData = theConstantInPool.getStringValue();
        byte[] theDataBytes = theData.getBytes();
        theGlobalVariables.add("stringPool" + i);
        theGlobalVariables.add("stringPool" + i + "__array");
        theWriter.print("      (set_global $stringPool");
        theWriter.print(i);
        theWriter.print("__array ");
        String theMethodName = WASMWriterUtils.toMethodName(BytecodeObjectTypeRef.fromRuntimeClass(MemoryManager.class), "newArray", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
        theWriter.print("(call $");
        theWriter.print(theMethodName);
        // UNUSED argument
        theWriter.print(" (i32.const 0) ");
        // Length
        theWriter.print(" (i32.const ");
        theWriter.print(theDataBytes.length);
        theWriter.print(")");
        // We also need the runtime class
        theWriter.print(" (get_global $");
        theWriter.print(WASMWriterUtils.toClassName(theArrayClass.getClassName()));
        theWriter.print("__runtimeClass");
        theWriter.print(")");
        // Plus the vtable index
        theWriter.print(" (i32.const ");
        theWriter.print(theResolver.resolveVTableMethodByType(BytecodeObjectTypeRef.fromRuntimeClass(Array.class)));
        theWriter.println(")))");
        // Set array value
        for (int j = 0; j < theDataBytes.length; j++) {
            // 
            int offset = 20 + j * 4;
            theWriter.print("      (i32.store ");
            theWriter.print("offset=" + offset + " ");
            theWriter.print("(get_global $stringPool");
            theWriter.print(i);
            theWriter.print("__array) ");
            theWriter.print("(i32.const ");
            theWriter.print(theDataBytes[j]);
            theWriter.println("))");
        }
        theWriter.print("      (set_global $stringPool");
        theWriter.print(i);
        theWriter.print(" (call $");
        theWriter.print(WASMWriterUtils.toClassName(theManagerClass.getClassName()));
        theWriter.print("_dmbcAddressnewObjectINTINTINT");
        // Unused argument
        theWriter.print(" (i32.const 0)");
        theWriter.print(" (i32.const ");
        theWriter.print(theStringMemoryLayout.instanceSize());
        theWriter.print(")");
        theWriter.print(" (i32.const ");
        theWriter.print(theStringClass.getUniqueId());
        theWriter.print(")");
        theWriter.print(" (i32.const ");
        theWriter.print(theResolver.resolveVTableMethodByType(theStringClass.getClassName()));
        theWriter.print(")");
        theWriter.println("))");
        theWriter.print("      (call $");
        theWriter.print(WASMWriterUtils.toClassName(theStringClass.getClassName()));
        theWriter.print("_VOIDinitA1BYTE ");
        theWriter.print(" (get_global $stringPool");
        theWriter.print(i);
        theWriter.print(")");
        theWriter.print(" (get_global $stringPool");
        theWriter.print(i);
        theWriter.println("__array))");
    }
    // After the Bootstrap, we need to all the static stuff on the stack, so it is not garbage collected
    theWriter.print("      (set_global $STACKTOP (i32.sub (get_global $STACKTOP) (i32.const ");
    theWriter.print(theGlobalVariables.size() * 4);
    theWriter.println(")))");
    for (int i = 0; i < theGlobalVariables.size(); i++) {
        theWriter.print("      (i32.store offset=");
        theWriter.print(i * 4);
        theWriter.print(" (get_global $STACKTOP) (get_global $");
        theWriter.print(theGlobalVariables.get(i));
        theWriter.println("))");
    }
    theWriter.println("   )");
    theWriter.println();
    for (int i = 0; i < thePoolValues.size(); i++) {
        theWriter.print("   (global $stringPool");
        theWriter.print(i);
        theWriter.println(" (mut i32) (i32.const 0))");
        theWriter.print("   (global $stringPool");
        theWriter.print(i);
        theWriter.println("__array (mut i32) (i32.const 0))");
    }
    theWriter.println("   (global $STACKTOP (mut i32) (i32.const 0))");
    // Globals for static class data
    aLinkerContext.linkedClasses().forEach(aEntry -> {
        if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
            return;
        }
        if (aEntry.targetNode().getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
            return;
        }
        theWriter.print("   (global $");
        theWriter.print(WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
        theWriter.println("__runtimeClass (mut i32) (i32.const 0))");
    });
    theWriter.println();
    theWriter.println("   (export \"bootstrap\" (func $bootstrap))");
    // Write exports
    aLinkerContext.linkedClasses().forEach(aEntry -> {
        BytecodeLinkedClass theLinkedClass = aEntry.targetNode();
        if (theLinkedClass.getBytecodeClass().getAccessFlags().isInterface()) {
            return;
        }
        BytecodeResolvedMethods theMethodMap = theLinkedClass.resolvedMethods();
        theMethodMap.stream().forEach(aMethodMapEntry -> {
            BytecodeMethod t = aMethodMapEntry.getValue();
            BytecodeAnnotation theExport = t.getAttributes().getAnnotationByType(Export.class.getName());
            if (theExport != null) {
                theWriter.print("   (export \"");
                theWriter.print(theExport.getElementValueByName("value").stringValue());
                theWriter.print("\" (func $");
                theWriter.print(WASMWriterUtils.toMethodName(aEntry.edgeType().objectTypeRef(), t.getName(), t.getSignature()));
                theWriter.println("))");
            }
        });
    });
    theWriter.print("   (export \"main\" (func $");
    theWriter.print(WASMWriterUtils.toMethodName(BytecodeObjectTypeRef.fromRuntimeClass(aEntryPointClass), aEntryPointMethodName, aEntryPointSignatue));
    theWriter.println("))");
    theWriter.println();
    for (Map.Entry<String, String> theEntry : theGlobalTypes.entrySet()) {
        theWriter.print("   (type $t_");
        theWriter.print(theEntry.getKey());
        theWriter.print(" ");
        theWriter.print(theEntry.getValue());
        theWriter.println(")");
    }
    theWriter.println(")");
    theWriter.flush();
    return new WASMCompileResult(aLinkerContext, theGeneratedFunctions, theStringWriter.toString(), theMemoryLayout);
}
Also used : BytecodeMethodSignature(de.mirkosertic.bytecoder.core.BytecodeMethodSignature) Address(de.mirkosertic.bytecoder.classlib.Address) HashMap(java.util.HashMap) BytecodeMethod(de.mirkosertic.bytecoder.core.BytecodeMethod) ArrayList(java.util.ArrayList) ProgramGenerator(de.mirkosertic.bytecoder.ssa.ProgramGenerator) BytecodeResolvedMethods(de.mirkosertic.bytecoder.core.BytecodeResolvedMethods) BytecodeLinkedClass(de.mirkosertic.bytecoder.core.BytecodeLinkedClass) StringValue(de.mirkosertic.bytecoder.ssa.StringValue) RegionNode(de.mirkosertic.bytecoder.ssa.RegionNode) BytecodeResolvedFields(de.mirkosertic.bytecoder.core.BytecodeResolvedFields) HashSet(java.util.HashSet) Program(de.mirkosertic.bytecoder.ssa.Program) BytecodeTypeRef(de.mirkosertic.bytecoder.core.BytecodeTypeRef) BytecodeArrayTypeRef(de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef) BytecodeClass(de.mirkosertic.bytecoder.core.BytecodeClass) BytecodeLinkedClass(de.mirkosertic.bytecoder.core.BytecodeLinkedClass) HashMap(java.util.HashMap) Map(java.util.Map) BytecodeAnnotation(de.mirkosertic.bytecoder.core.BytecodeAnnotation) BytecodeVirtualMethodIdentifier(de.mirkosertic.bytecoder.core.BytecodeVirtualMethodIdentifier) Variable(de.mirkosertic.bytecoder.ssa.Variable) StringWriter(java.io.StringWriter) Export(de.mirkosertic.bytecoder.api.Export) PrintWriter(java.io.PrintWriter) MemoryManager(de.mirkosertic.bytecoder.classlib.MemoryManager) Array(java.lang.reflect.Array) BytecodeObjectTypeRef(de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef) Relooper(de.mirkosertic.bytecoder.relooper.Relooper) ConstantPool(de.mirkosertic.bytecoder.backend.ConstantPool) BytecodeImportedLink(de.mirkosertic.bytecoder.core.BytecodeImportedLink) BytecodeClass(de.mirkosertic.bytecoder.core.BytecodeClass)

Example 10 with Program

use of de.mirkosertic.bytecoder.ssa.Program in project Bytecoder by mirkosertic.

the class InlineGotoOptimizerTest method testSimpleFlowTwoLevels.

@Test
public void testSimpleFlowTwoLevels() {
    Program theProgram = new Program();
    ControlFlowGraph theGraph = theProgram.getControlFlowGraph();
    RegionNode theNode = theGraph.createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
    RegionNode theNode1 = theGraph.createAt(new BytecodeOpcodeAddress(20), RegionNode.BlockType.NORMAL);
    RegionNode theNode2 = theGraph.createAt(new BytecodeOpcodeAddress(40), RegionNode.BlockType.NORMAL);
    theNode.getExpressions().add(new GotoExpression(new BytecodeOpcodeAddress(20)));
    theNode.addSuccessor(theNode1);
    theNode1.getExpressions().add(new GotoExpression(new BytecodeOpcodeAddress(40)));
    theNode1.addSuccessor(theNode2);
    theNode2.getExpressions().add(new ReturnExpression());
    theGraph.calculateReachabilityAndMarkBackEdges();
    InlineGotoOptimizer theOptimizer = new InlineGotoOptimizer();
    theOptimizer.optimize(theGraph, null);
    Assert.assertEquals(1, theGraph.getKnownNodes().size(), 0);
    Assert.assertEquals(1, theGraph.getDominatedNodes().size(), 0);
    Assert.assertTrue(theGraph.getKnownNodes().contains(theNode));
    Assert.assertEquals(1, theNode.getExpressions().size(), 0);
    Assert.assertTrue(theNode.getExpressions().toList().get(0) instanceof ReturnExpression);
    Assert.assertEquals(0, theNode.getSuccessors().size(), 0);
    Relooper theRelooper = new Relooper();
    Relooper.Block theRoot = theRelooper.reloop(theGraph);
}
Also used : ReturnExpression(de.mirkosertic.bytecoder.ssa.ReturnExpression) Program(de.mirkosertic.bytecoder.ssa.Program) GotoExpression(de.mirkosertic.bytecoder.ssa.GotoExpression) Relooper(de.mirkosertic.bytecoder.relooper.Relooper) ControlFlowGraph(de.mirkosertic.bytecoder.ssa.ControlFlowGraph) BytecodeOpcodeAddress(de.mirkosertic.bytecoder.core.BytecodeOpcodeAddress) RegionNode(de.mirkosertic.bytecoder.ssa.RegionNode) Test(org.junit.Test)

Aggregations

Program (de.mirkosertic.bytecoder.ssa.Program)14 RegionNode (de.mirkosertic.bytecoder.ssa.RegionNode)11 ControlFlowGraph (de.mirkosertic.bytecoder.ssa.ControlFlowGraph)9 Test (org.junit.Test)9 BytecodeOpcodeAddress (de.mirkosertic.bytecoder.core.BytecodeOpcodeAddress)8 GotoExpression (de.mirkosertic.bytecoder.ssa.GotoExpression)6 ReturnExpression (de.mirkosertic.bytecoder.ssa.ReturnExpression)6 Relooper (de.mirkosertic.bytecoder.relooper.Relooper)5 Variable (de.mirkosertic.bytecoder.ssa.Variable)5 BytecodeMethodSignature (de.mirkosertic.bytecoder.core.BytecodeMethodSignature)4 BytecodeLinkedClass (de.mirkosertic.bytecoder.core.BytecodeLinkedClass)3 BytecodeMethod (de.mirkosertic.bytecoder.core.BytecodeMethod)3 BytecodeObjectTypeRef (de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef)3 BytecodeResolvedMethods (de.mirkosertic.bytecoder.core.BytecodeResolvedMethods)3 BytecodeTypeRef (de.mirkosertic.bytecoder.core.BytecodeTypeRef)3 ProgramGenerator (de.mirkosertic.bytecoder.ssa.ProgramGenerator)3 PrintWriter (java.io.PrintWriter)3 StringWriter (java.io.StringWriter)3 ConstantPool (de.mirkosertic.bytecoder.backend.ConstantPool)2 BytecodeArrayTypeRef (de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef)2