Search in sources :

Example 1 with BytecodeArrayTypeRef

use of de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef in project Bytecoder by mirkosertic.

the class BytecoderMavenMojo method execute.

@Override
public void execute() throws MojoExecutionException, MojoFailureException {
    File theBaseDirectory = new File(buldDirectory);
    File theBytecoderDirectory = new File(theBaseDirectory, "bytecoder");
    theBytecoderDirectory.mkdirs();
    try {
        ClassLoader theLoader = prepareClassLoader();
        Class theTargetClass = theLoader.loadClass(mainClass);
        CompileTarget theCompileTarget = new CompileTarget(theLoader, CompileTarget.BackendType.valueOf(backend));
        File theBytecoderFileName = new File(theBytecoderDirectory, theCompileTarget.generatedFileName());
        BytecodeMethodSignature theSignature = new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[] { new BytecodeArrayTypeRef(BytecodeObjectTypeRef.fromRuntimeClass(String.class), 1) });
        CompileOptions theOptions = new CompileOptions(new Slf4JLogger(), debugOutput, KnownOptimizer.ALL);
        CompileResult theCode = theCompileTarget.compileToJS(theOptions, theTargetClass, "main", theSignature);
        try (PrintWriter theWriter = new PrintWriter(new FileWriter(theBytecoderFileName))) {
            theWriter.println(theCode.getData());
        }
        if (optimizeWithGoogleClosure) {
            Compiler theCompiler = new Compiler();
            CompilerOptions theClosureOptions = new CompilerOptions();
            theClosureOptions.setLanguageIn(CompilerOptions.LanguageMode.ECMASCRIPT5_STRICT);
            theClosureOptions.setLanguageOut(CompilerOptions.LanguageMode.ECMASCRIPT5_STRICT);
            CompilationLevel.valueOf(closureOptimizationLevel).setOptionsForCompilationLevel(theClosureOptions);
            List<SourceFile> theSourceFiles = CommandLineRunner.getBuiltinExterns(CompilerOptions.Environment.BROWSER);
            theSourceFiles.add(SourceFile.fromCode("bytecoder.js", (String) theCode.getData()));
            theCompiler.compile(new ArrayList<>(), theSourceFiles, theClosureOptions);
            String theClosureCode = theCompiler.toSource();
            File theBytecoderClosureFileName = new File(theBytecoderDirectory, "bytecoder-closure.js");
            try (PrintWriter theWriter = new PrintWriter(new FileWriter(theBytecoderClosureFileName))) {
                theWriter.println(theClosureCode);
            }
        }
        if (theCode instanceof WASMCompileResult) {
            WASMCompileResult theWASMCompileResult = (WASMCompileResult) theCode;
            int[] theWASM = wat2wasm(theWASMCompileResult);
            File theBytecoderWASMFileName = new File(theBytecoderDirectory, "bytecoder.wasm");
            try (FileOutputStream theFos = new FileOutputStream(theBytecoderWASMFileName)) {
                for (int aTheWASM : theWASM) {
                    theFos.write(aTheWASM);
                }
            }
        }
    } catch (Exception e) {
        throw new MojoExecutionException("Error running bytecoder", e);
    }
}
Also used : Compiler(com.google.javascript.jscomp.Compiler) BytecodeMethodSignature(de.mirkosertic.bytecoder.core.BytecodeMethodSignature) WASMCompileResult(de.mirkosertic.bytecoder.backend.wasm.WASMCompileResult) MojoExecutionException(org.apache.maven.plugin.MojoExecutionException) FileWriter(java.io.FileWriter) CompileOptions(de.mirkosertic.bytecoder.backend.CompileOptions) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException) MojoExecutionException(org.apache.maven.plugin.MojoExecutionException) MojoFailureException(org.apache.maven.plugin.MojoFailureException) BytecodeArrayTypeRef(de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef) FileOutputStream(java.io.FileOutputStream) CompileTarget(de.mirkosertic.bytecoder.backend.CompileTarget) CompilerOptions(com.google.javascript.jscomp.CompilerOptions) URLClassLoader(java.net.URLClassLoader) WASMCompileResult(de.mirkosertic.bytecoder.backend.wasm.WASMCompileResult) CompileResult(de.mirkosertic.bytecoder.backend.CompileResult) SourceFile(com.google.javascript.jscomp.SourceFile) SourceFile(com.google.javascript.jscomp.SourceFile) File(java.io.File) Slf4JLogger(de.mirkosertic.bytecoder.unittest.Slf4JLogger) PrintWriter(java.io.PrintWriter)

Example 2 with BytecodeArrayTypeRef

use of de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef in project Bytecoder by mirkosertic.

the class NaiveProgramGenerator method initializeBlockWith.

private void initializeBlockWith(BytecodeClass aOwningClass, BytecodeMethod aMethod, RegionNode aTargetBlock, Function<BytecodeOpcodeAddress, BytecodeBasicBlock> aBlocksByAddress, ParsingHelper aHelper) {
    // Finally we can start to parse the program
    BytecodeBasicBlock theBytecodeBlock = aBlocksByAddress.apply(aTargetBlock.getStartAddress());
    for (BytecodeInstruction theInstruction : theBytecodeBlock.getInstructions()) {
        if (theInstruction instanceof BytecodeInstructionNOP) {
            BytecodeInstructionNOP theINS = (BytecodeInstructionNOP) theInstruction;
        // Completely ignored
        } else if (theInstruction instanceof BytecodeInstructionMONITORENTER) {
            BytecodeInstructionMONITORENTER theINS = (BytecodeInstructionMONITORENTER) theInstruction;
            // Pop the reference for the lock from the stack
            aHelper.pop();
        // Completely ignored
        } else if (theInstruction instanceof BytecodeInstructionMONITOREXIT) {
            BytecodeInstructionMONITOREXIT theINS = (BytecodeInstructionMONITOREXIT) theInstruction;
            // Pop the reference for the lock from the stack
            aHelper.pop();
        // Completely ignored
        } else if (theInstruction instanceof BytecodeInstructionCHECKCAST) {
            BytecodeInstructionCHECKCAST theINS = (BytecodeInstructionCHECKCAST) theInstruction;
            Value theValue = aHelper.peek();
            aTargetBlock.getExpressions().add(new CheckCastExpression(theValue, theINS.getTypeCheck()));
        } else if (theInstruction instanceof BytecodeInstructionPOP) {
            BytecodeInstructionPOP theINS = (BytecodeInstructionPOP) theInstruction;
            aHelper.pop();
        } else if (theInstruction instanceof BytecodeInstructionPOP2) {
            BytecodeInstructionPOP2 theINS = (BytecodeInstructionPOP2) theInstruction;
            Value theValue = aHelper.pop();
            switch(theValue.resolveType().resolve()) {
                case LONG:
                    break;
                case DOUBLE:
                    break;
                default:
                    aHelper.pop();
            }
        } else if (theInstruction instanceof BytecodeInstructionDUP) {
            BytecodeInstructionDUP theINS = (BytecodeInstructionDUP) theInstruction;
            Value theValue = aHelper.peek();
            aHelper.push(theValue);
        } else if (theInstruction instanceof BytecodeInstructionDUP2) {
            BytecodeInstructionDUP2 theINS = (BytecodeInstructionDUP2) theInstruction;
            Value theValue1 = aHelper.pop();
            if (theValue1.resolveType().resolve() == TypeRef.Native.LONG || theValue1.resolveType().resolve() == TypeRef.Native.DOUBLE) {
                // Category 2
                aHelper.push(theValue1);
                aHelper.push(theValue1);
            } else {
                // Category 1
                Value theValue2 = aHelper.pop();
                aHelper.push(theValue2);
                aHelper.push(theValue1);
                aHelper.push(theValue2);
                aHelper.push(theValue1);
            }
        } else if (theInstruction instanceof BytecodeInstructionDUP2X1) {
            BytecodeInstructionDUP2X1 theINS = (BytecodeInstructionDUP2X1) theInstruction;
            Value theValue1 = aHelper.pop();
            if (theValue1.resolveType().resolve() == TypeRef.Native.LONG || theValue1.resolveType().resolve() == TypeRef.Native.DOUBLE) {
                Value theValue2 = aHelper.pop();
                aHelper.push(theValue1);
                aHelper.push(theValue2);
                aHelper.push(theValue2);
            } else {
                Value theValue2 = aHelper.pop();
                Value theValue3 = aHelper.pop();
                aHelper.push(theValue2);
                aHelper.push(theValue1);
                aHelper.push(theValue3);
                aHelper.push(theValue2);
                aHelper.push(theValue2);
            }
        } else if (theInstruction instanceof BytecodeInstructionDUPX1) {
            BytecodeInstructionDUPX1 theINS = (BytecodeInstructionDUPX1) theInstruction;
            Value theValue1 = aHelper.pop();
            Value theValue2 = aHelper.pop();
            aHelper.push(theValue1);
            aHelper.push(theValue2);
            aHelper.push(theValue1);
        } else if (theInstruction instanceof BytecodeInstructionDUPX2) {
            BytecodeInstructionDUPX2 theINS = (BytecodeInstructionDUPX2) theInstruction;
            Value theValue1 = aHelper.pop();
            Value theValue2 = aHelper.pop();
            if (theValue2.resolveType().resolve() == TypeRef.Native.LONG || theValue2.resolveType().resolve() == TypeRef.Native.DOUBLE) {
                // Form 2
                aHelper.push(theValue1);
                aHelper.push(theValue2);
                aHelper.push(theValue1);
            } else {
                // Form 1
                Value theValue3 = aHelper.pop();
                aHelper.push(theValue1);
                aHelper.push(theValue3);
                aHelper.push(theValue2);
                aHelper.push(theValue1);
            }
        } else if (theInstruction instanceof BytecodeInstructionGETSTATIC) {
            BytecodeInstructionGETSTATIC theINS = (BytecodeInstructionGETSTATIC) theInstruction;
            GetStaticExpression theValue = new GetStaticExpression(theINS.getConstant());
            Variable theVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getConstant().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().fieldType()), theValue);
            aHelper.push(theVariable);
        } else if (theInstruction instanceof BytecodeInstructionASTORE) {
            BytecodeInstructionASTORE theINS = (BytecodeInstructionASTORE) theInstruction;
            Value theValue = aHelper.pop();
            aHelper.setLocalVariable(theInstruction.getOpcodeAddress(), theINS.getVariableIndex(), theValue);
        } else if (theInstruction instanceof BytecodeInstructionGenericSTORE) {
            BytecodeInstructionGenericSTORE theINS = (BytecodeInstructionGenericSTORE) theInstruction;
            Value theValue = aHelper.pop();
            Variable theOtherVariable = aTargetBlock.newVariable(theValue.resolveType().resolve(), theValue);
            aHelper.setLocalVariable(theInstruction.getOpcodeAddress(), theINS.getVariableIndex(), theOtherVariable);
        } else if (theInstruction instanceof BytecodeInstructionObjectArrayLOAD) {
            BytecodeInstructionObjectArrayLOAD theINS = (BytecodeInstructionObjectArrayLOAD) theInstruction;
            Value theIndex = aHelper.pop();
            Value theTarget = aHelper.pop();
            TypeRef theType = theTarget.resolveType();
            if (theType instanceof TypeRef.ArrayTypeRef) {
                TypeRef.ArrayTypeRef theArrayTypeRef = (TypeRef.ArrayTypeRef) theTarget.resolveType();
                Variable theVariable = aTargetBlock.newVariable(TypeRef.toType(theArrayTypeRef.arrayType()), new ArrayEntryExpression(TypeRef.Native.REFERENCE, theTarget, theIndex));
                aHelper.push(theVariable);
            } else {
                Variable theVariable = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, new ArrayEntryExpression(TypeRef.Native.REFERENCE, theTarget, theIndex));
                aHelper.push(theVariable);
            }
        } else if (theInstruction instanceof BytecodeInstructionGenericArrayLOAD) {
            BytecodeInstructionGenericArrayLOAD theINS = (BytecodeInstructionGenericArrayLOAD) theInstruction;
            Value theIndex = aHelper.pop();
            Value theTarget = aHelper.pop();
            Variable theVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new ArrayEntryExpression(TypeRef.toType(theINS.getType()), theTarget, theIndex));
            aHelper.push(theVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericArraySTORE) {
            BytecodeInstructionGenericArraySTORE theINS = (BytecodeInstructionGenericArraySTORE) theInstruction;
            Value theValue = aHelper.pop();
            Value theIndex = aHelper.pop();
            Value theTarget = aHelper.pop();
            aTargetBlock.getExpressions().add(new ArrayStoreExpression(TypeRef.toType(theINS.getType()), theTarget, theIndex, theValue));
        } else if (theInstruction instanceof BytecodeInstructionObjectArraySTORE) {
            BytecodeInstructionObjectArraySTORE theINS = (BytecodeInstructionObjectArraySTORE) theInstruction;
            Value theValue = aHelper.pop();
            Value theIndex = aHelper.pop();
            Value theTarget = aHelper.pop();
            aTargetBlock.getExpressions().add(new ArrayStoreExpression(TypeRef.Native.REFERENCE, theTarget, theIndex, theValue));
        } else if (theInstruction instanceof BytecodeInstructionACONSTNULL) {
            BytecodeInstructionACONSTNULL theINS = (BytecodeInstructionACONSTNULL) theInstruction;
            aHelper.push(new NullValue());
        } else if (theInstruction instanceof BytecodeInstructionPUTFIELD) {
            BytecodeInstructionPUTFIELD theINS = (BytecodeInstructionPUTFIELD) theInstruction;
            Value theValue = aHelper.pop();
            Value theTarget = aHelper.pop();
            aTargetBlock.getExpressions().add(new PutFieldExpression(theINS.getFieldRefConstant(), theTarget, theValue));
        } else if (theInstruction instanceof BytecodeInstructionGETFIELD) {
            BytecodeInstructionGETFIELD theINS = (BytecodeInstructionGETFIELD) theInstruction;
            Value theTarget = aHelper.pop();
            Variable theVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getFieldRefConstant().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().fieldType()), new GetFieldExpression(theINS.getFieldRefConstant(), theTarget));
            aHelper.push(theVariable);
        } else if (theInstruction instanceof BytecodeInstructionPUTSTATIC) {
            BytecodeInstructionPUTSTATIC theINS = (BytecodeInstructionPUTSTATIC) theInstruction;
            Value theValue = aHelper.pop();
            aTargetBlock.getExpressions().add(new PutStaticExpression(theINS.getConstant(), theValue));
        } else if (theInstruction instanceof BytecodeInstructionGenericLDC) {
            BytecodeInstructionGenericLDC theINS = (BytecodeInstructionGenericLDC) theInstruction;
            BytecodeConstant theConstant = theINS.constant();
            if (theConstant instanceof BytecodeDoubleConstant) {
                BytecodeDoubleConstant theC = (BytecodeDoubleConstant) theConstant;
                aHelper.push(new DoubleValue(theC.getDoubleValue()));
            } else if (theConstant instanceof BytecodeLongConstant) {
                BytecodeLongConstant theC = (BytecodeLongConstant) theConstant;
                aHelper.push(new LongValue(theC.getLongValue()));
            } else if (theConstant instanceof BytecodeFloatConstant) {
                BytecodeFloatConstant theC = (BytecodeFloatConstant) theConstant;
                aHelper.push(new FloatValue(theC.getFloatValue()));
            } else if (theConstant instanceof BytecodeIntegerConstant) {
                BytecodeIntegerConstant theC = (BytecodeIntegerConstant) theConstant;
                aHelper.push(new IntegerValue(theC.getIntegerValue()));
            } else if (theConstant instanceof BytecodeStringConstant) {
                BytecodeStringConstant theC = (BytecodeStringConstant) theConstant;
                Variable theVariable = aTargetBlock.newVariable(TypeRef.toType(BytecodeObjectTypeRef.fromRuntimeClass(String.class)), new StringValue(theC.getValue().stringValue()));
                aHelper.push(theVariable);
            } else if (theConstant instanceof BytecodeClassinfoConstant) {
                BytecodeClassinfoConstant theC = (BytecodeClassinfoConstant) theConstant;
                BytecodeUtf8Constant theUTF8 = theC.getConstant();
                if (theUTF8.stringValue().startsWith("[")) {
                    aHelper.push(new ClassReferenceValue(BytecodeObjectTypeRef.fromRuntimeClass(Array.class)));
                } else {
                    aHelper.push(new ClassReferenceValue(BytecodeObjectTypeRef.fromUtf8Constant(theC.getConstant())));
                }
            } else {
                throw new IllegalArgumentException("Unsupported constant type : " + theConstant);
            }
        } else if (theInstruction instanceof BytecodeInstructionBIPUSH) {
            BytecodeInstructionBIPUSH theINS = (BytecodeInstructionBIPUSH) theInstruction;
            aHelper.push(new IntegerValue(theINS.getByteValue()));
        } else if (theInstruction instanceof BytecodeInstructionSIPUSH) {
            BytecodeInstructionSIPUSH theINS = (BytecodeInstructionSIPUSH) theInstruction;
            aHelper.push(new IntegerValue(theINS.getShortValue()));
        } else if (theInstruction instanceof BytecodeInstructionICONST) {
            BytecodeInstructionICONST theINS = (BytecodeInstructionICONST) theInstruction;
            aHelper.push(new IntegerValue(theINS.getIntConst()));
        } else if (theInstruction instanceof BytecodeInstructionFCONST) {
            BytecodeInstructionFCONST theINS = (BytecodeInstructionFCONST) theInstruction;
            aHelper.push(new FloatValue(theINS.getFloatValue()));
        } else if (theInstruction instanceof BytecodeInstructionDCONST) {
            BytecodeInstructionDCONST theINS = (BytecodeInstructionDCONST) theInstruction;
            aHelper.push(new DoubleValue(theINS.getDoubleConst()));
        } else if (theInstruction instanceof BytecodeInstructionLCONST) {
            BytecodeInstructionLCONST theINS = (BytecodeInstructionLCONST) theInstruction;
            aHelper.push(new LongValue(theINS.getLongConst()));
        } else if (theInstruction instanceof BytecodeInstructionGenericNEG) {
            BytecodeInstructionGenericNEG theINS = (BytecodeInstructionGenericNEG) theInstruction;
            Value theValue = aHelper.pop();
            Variable theNegatedValue = aTargetBlock.newVariable(theValue.resolveType(), new NegatedExpression(theValue));
            aHelper.push(theNegatedValue);
        } else if (theInstruction instanceof BytecodeInstructionARRAYLENGTH) {
            BytecodeInstructionARRAYLENGTH theINS = (BytecodeInstructionARRAYLENGTH) theInstruction;
            Value theValue = aHelper.pop();
            Variable theNegatedValue = aTargetBlock.newVariable(TypeRef.Native.INT, new ArrayLengthExpression(theValue));
            aHelper.push(theNegatedValue);
        } else if (theInstruction instanceof BytecodeInstructionGenericLOAD) {
            BytecodeInstructionGenericLOAD theINS = (BytecodeInstructionGenericLOAD) theInstruction;
            Value theValue = aHelper.getLocalVariable(theINS.getVariableIndex());
            aHelper.push(theValue);
        } else if (theInstruction instanceof BytecodeInstructionALOAD) {
            BytecodeInstructionALOAD theINS = (BytecodeInstructionALOAD) theInstruction;
            Value theValue = aHelper.getLocalVariable(theINS.getVariableIndex());
            aHelper.push(theValue);
        } else if (theInstruction instanceof BytecodeInstructionGenericCMP) {
            BytecodeInstructionGenericCMP theINS = (BytecodeInstructionGenericCMP) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT, new CompareExpression(theValue1, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionLCMP) {
            BytecodeInstructionLCMP theINS = (BytecodeInstructionLCMP) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT, new CompareExpression(theValue1, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionIINC) {
            BytecodeInstructionIINC theINS = (BytecodeInstructionIINC) theInstruction;
            Value theValueToIncrement = aHelper.getLocalVariable(theINS.getIndex());
            Value theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT, new BinaryExpression(TypeRef.Native.INT, theValueToIncrement, BinaryExpression.Operator.ADD, new IntegerValue(theINS.getConstant())));
            aHelper.setLocalVariable(theInstruction.getOpcodeAddress(), theINS.getIndex(), theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericREM) {
            BytecodeInstructionGenericREM theINS = (BytecodeInstructionGenericREM) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.REMAINDER, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericADD) {
            BytecodeInstructionGenericADD theINS = (BytecodeInstructionGenericADD) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.ADD, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericDIV) {
            BytecodeInstructionGenericDIV theINS = (BytecodeInstructionGenericDIV) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable;
            Value theDivValue = new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.DIV, theValue2);
            switch(theINS.getType()) {
                case FLOAT:
                    theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), theDivValue);
                    break;
                case DOUBLE:
                    theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), theDivValue);
                    break;
                default:
                    theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new FloorExpression(theDivValue, TypeRef.toType(theINS.getType())));
                    break;
            }
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericMUL) {
            BytecodeInstructionGenericMUL theINS = (BytecodeInstructionGenericMUL) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.MUL, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericSUB) {
            BytecodeInstructionGenericSUB theINS = (BytecodeInstructionGenericSUB) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.SUB, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericXOR) {
            BytecodeInstructionGenericXOR theINS = (BytecodeInstructionGenericXOR) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.BINARYXOR, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericOR) {
            BytecodeInstructionGenericOR theINS = (BytecodeInstructionGenericOR) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.BINARYOR, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericAND) {
            BytecodeInstructionGenericAND theINS = (BytecodeInstructionGenericAND) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.BINARYAND, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericSHL) {
            BytecodeInstructionGenericSHL theINS = (BytecodeInstructionGenericSHL) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.BINARYSHIFTLEFT, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericSHR) {
            BytecodeInstructionGenericSHR theINS = (BytecodeInstructionGenericSHR) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.BINARYSHIFTRIGHT, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGenericUSHR) {
            BytecodeInstructionGenericUSHR theINS = (BytecodeInstructionGenericUSHR) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getType()), new BinaryExpression(TypeRef.toType(theINS.getType()), theValue1, BinaryExpression.Operator.BINARYUNSIGNEDSHIFTRIGHT, theValue2));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionIFNULL) {
            BytecodeInstructionIFNULL theINS = (BytecodeInstructionIFNULL) theInstruction;
            Value theValue = aHelper.pop();
            FixedBinaryExpression theBinaryValue = new FixedBinaryExpression(theValue, FixedBinaryExpression.Operator.ISNULL);
            ExpressionList theExpressions = new ExpressionList();
            theExpressions.add(new GotoExpression(theINS.getJumpTarget()));
            aTargetBlock.getExpressions().add(new IFExpression(theINS.getOpcodeAddress(), theINS.getJumpTarget(), theBinaryValue, theExpressions));
        } else if (theInstruction instanceof BytecodeInstructionIFNONNULL) {
            BytecodeInstructionIFNONNULL theINS = (BytecodeInstructionIFNONNULL) theInstruction;
            Value theValue = aHelper.pop();
            FixedBinaryExpression theBinaryValue = new FixedBinaryExpression(theValue, FixedBinaryExpression.Operator.ISNONNULL);
            ExpressionList theExpressions = new ExpressionList();
            theExpressions.add(new GotoExpression(theINS.getJumpTarget()));
            aTargetBlock.getExpressions().add(new IFExpression(theINS.getOpcodeAddress(), theINS.getJumpTarget(), theBinaryValue, theExpressions));
        } else if (theInstruction instanceof BytecodeInstructionIFICMP) {
            BytecodeInstructionIFICMP theINS = (BytecodeInstructionIFICMP) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            BinaryExpression theBinaryValue;
            switch(theINS.getType()) {
                case lt:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue1, BinaryExpression.Operator.LESSTHAN, theValue2);
                    break;
                case eq:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue1, BinaryExpression.Operator.EQUALS, theValue2);
                    break;
                case gt:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue1, BinaryExpression.Operator.GREATERTHAN, theValue2);
                    break;
                case ge:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue1, BinaryExpression.Operator.GREATEROREQUALS, theValue2);
                    break;
                case le:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue1, BinaryExpression.Operator.LESSTHANOREQUALS, theValue2);
                    break;
                case ne:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue1, BinaryExpression.Operator.NOTEQUALS, theValue2);
                    break;
                default:
                    throw new IllegalStateException("Not supported operation : " + theINS.getType());
            }
            ExpressionList theExpressions = new ExpressionList();
            theExpressions.add(new GotoExpression(theINS.getJumpTarget()));
            aTargetBlock.getExpressions().add(new IFExpression(theINS.getOpcodeAddress(), theINS.getJumpTarget(), theBinaryValue, theExpressions));
        } else if (theInstruction instanceof BytecodeInstructionIFACMP) {
            BytecodeInstructionIFACMP theINS = (BytecodeInstructionIFACMP) theInstruction;
            Value theValue2 = aHelper.pop();
            Value theValue1 = aHelper.pop();
            BinaryExpression theBinaryValue;
            switch(theINS.getType()) {
                case eq:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue1, BinaryExpression.Operator.EQUALS, theValue2);
                    break;
                case ne:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue1, BinaryExpression.Operator.NOTEQUALS, theValue2);
                    break;
                default:
                    throw new IllegalStateException("Not supported operation : " + theINS.getType());
            }
            ExpressionList theExpressions = new ExpressionList();
            theExpressions.add(new GotoExpression(theINS.getJumpTarget()));
            aTargetBlock.getExpressions().add(new IFExpression(theINS.getOpcodeAddress(), theINS.getJumpTarget(), theBinaryValue, theExpressions));
        } else if (theInstruction instanceof BytecodeInstructionIFCOND) {
            BytecodeInstructionIFCOND theINS = (BytecodeInstructionIFCOND) theInstruction;
            Value theValue = aHelper.pop();
            BinaryExpression theBinaryValue;
            switch(theINS.getType()) {
                case lt:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue, BinaryExpression.Operator.LESSTHAN, new IntegerValue(0));
                    break;
                case eq:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue, BinaryExpression.Operator.EQUALS, new IntegerValue(0));
                    break;
                case gt:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue, BinaryExpression.Operator.GREATERTHAN, new IntegerValue(0));
                    break;
                case ge:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue, BinaryExpression.Operator.GREATEROREQUALS, new IntegerValue(0));
                    break;
                case le:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue, BinaryExpression.Operator.LESSTHANOREQUALS, new IntegerValue(0));
                    break;
                case ne:
                    theBinaryValue = new BinaryExpression(TypeRef.Native.BOOLEAN, theValue, BinaryExpression.Operator.NOTEQUALS, new IntegerValue(0));
                    break;
                default:
                    throw new IllegalStateException("Not supported operation : " + theINS.getType());
            }
            ExpressionList theExpressions = new ExpressionList();
            theExpressions.add(new GotoExpression(theINS.getJumpTarget()));
            aTargetBlock.getExpressions().add(new IFExpression(theINS.getOpcodeAddress(), theINS.getJumpTarget(), theBinaryValue, theExpressions));
        } else if (theInstruction instanceof BytecodeInstructionObjectRETURN) {
            BytecodeInstructionObjectRETURN theINS = (BytecodeInstructionObjectRETURN) theInstruction;
            Value theValue = aHelper.pop();
            aTargetBlock.getExpressions().add(new ReturnValueExpression(theValue));
        } else if (theInstruction instanceof BytecodeInstructionGenericRETURN) {
            BytecodeInstructionGenericRETURN theINS = (BytecodeInstructionGenericRETURN) theInstruction;
            Value theValue = aHelper.pop();
            aTargetBlock.getExpressions().add(new ReturnValueExpression(theValue));
        } else if (theInstruction instanceof BytecodeInstructionATHROW) {
            BytecodeInstructionATHROW theINS = (BytecodeInstructionATHROW) theInstruction;
            Value theValue = aHelper.pop();
            aTargetBlock.getExpressions().add(new ThrowExpression(theValue));
        } else if (theInstruction instanceof BytecodeInstructionRETURN) {
            BytecodeInstructionRETURN theINS = (BytecodeInstructionRETURN) theInstruction;
            aTargetBlock.getExpressions().add(new ReturnExpression());
        } else if (theInstruction instanceof BytecodeInstructionNEW) {
            BytecodeInstructionNEW theINS = (BytecodeInstructionNEW) theInstruction;
            BytecodeClassinfoConstant theClassInfo = theINS.getClassInfoForObjectToCreate();
            BytecodeObjectTypeRef theObjectType = BytecodeObjectTypeRef.fromUtf8Constant(theClassInfo.getConstant());
            if (Objects.equals(theObjectType.name(), Address.class.getName())) {
                // At this time the exact location is unknown, the value
                // will be set at constructor invocation time
                Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT);
                aHelper.push(theNewVariable);
            } else {
                if (Objects.equals(theObjectType, BytecodeObjectTypeRef.fromRuntimeClass(VM.RuntimeGeneratedType.class))) {
                    Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, new RuntimeGeneratedTypeExpression());
                    aHelper.push(theNewVariable);
                } else {
                    Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theObjectType), new NewObjectExpression(theClassInfo));
                    aHelper.push(theNewVariable);
                }
            }
        } else if (theInstruction instanceof BytecodeInstructionNEWARRAY) {
            BytecodeInstructionNEWARRAY theINS = (BytecodeInstructionNEWARRAY) theInstruction;
            Value theLength = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, new NewArrayExpression(theINS.getPrimitiveType(), theLength));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionNEWMULTIARRAY) {
            BytecodeInstructionNEWMULTIARRAY theINS = (BytecodeInstructionNEWMULTIARRAY) theInstruction;
            List<Value> theDimensions = new ArrayList<>();
            for (int i = 0; i < theINS.getDimensions(); i++) {
                theDimensions.add(aHelper.pop());
            }
            Collections.reverse(theDimensions);
            BytecodeTypeRef theTypeRef = linkerContext.getSignatureParser().toFieldType(new BytecodeUtf8Constant(theINS.getTypeConstant().getConstant().stringValue()));
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, new NewMultiArrayExpression(theTypeRef, theDimensions));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionANEWARRAY) {
            BytecodeInstructionANEWARRAY theINS = (BytecodeInstructionANEWARRAY) theInstruction;
            Value theLength = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, new NewArrayExpression(theINS.getObjectType(), theLength));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionGOTO) {
            BytecodeInstructionGOTO theINS = (BytecodeInstructionGOTO) theInstruction;
            aTargetBlock.getExpressions().add(new GotoExpression(theINS.getJumpAddress()));
        } else if (theInstruction instanceof BytecodeInstructionL2Generic) {
            BytecodeInstructionL2Generic theINS = (BytecodeInstructionL2Generic) theInstruction;
            Value theValue = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getTargetType()), new TypeConversionExpression(theValue, TypeRef.toType(theINS.getTargetType())));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionI2Generic) {
            BytecodeInstructionI2Generic theINS = (BytecodeInstructionI2Generic) theInstruction;
            Value theValue = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getTargetType()), new TypeConversionExpression(theValue, TypeRef.toType(theINS.getTargetType())));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionF2Generic) {
            BytecodeInstructionF2Generic theINS = (BytecodeInstructionF2Generic) theInstruction;
            Value theValue = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getTargetType()), new TypeConversionExpression(theValue, TypeRef.toType(theINS.getTargetType())));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionD2Generic) {
            BytecodeInstructionD2Generic theINS = (BytecodeInstructionD2Generic) theInstruction;
            Value theValue = aHelper.pop();
            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theINS.getTargetType()), new TypeConversionExpression(theValue, TypeRef.toType(theINS.getTargetType())));
            aHelper.push(theNewVariable);
        } else if (theInstruction instanceof BytecodeInstructionINVOKESPECIAL) {
            BytecodeInstructionINVOKESPECIAL theINS = (BytecodeInstructionINVOKESPECIAL) theInstruction;
            BytecodeMethodSignature theSignature = theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
            List<Value> theArguments = new ArrayList<>();
            BytecodeTypeRef[] theArgumentTypes = theSignature.getArguments();
            for (BytecodeTypeRef theArgumentType : theArgumentTypes) {
                theArguments.add(aHelper.pop());
            }
            Collections.reverse(theArguments);
            Variable theTarget = (Variable) aHelper.pop();
            BytecodeObjectTypeRef theType = BytecodeObjectTypeRef.fromUtf8Constant(theINS.getMethodReference().getClassIndex().getClassConstant().getConstant());
            if (Objects.equals(theType, BytecodeObjectTypeRef.fromRuntimeClass(VM.RuntimeGeneratedType.class))) {
                RuntimeGeneratedTypeExpression theValue = (RuntimeGeneratedTypeExpression) theTarget.incomingDataFlows().get(0);
                theValue.setType(theArguments.get(0));
                theValue.setMethodRef(theArguments.get(1));
            } else if (Objects.equals(theType, BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
                theTarget.initializeWith(theArguments.get(0));
                aTargetBlock.getExpressions().add(new VariableAssignmentExpression(theTarget, theArguments.get(0)));
            } else {
                String theMethodName = theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue();
                if ("getClass".equals(theMethodName) && BytecodeLinkedClass.GET_CLASS_SIGNATURE.metchesExactlyTo(theSignature)) {
                    Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theSignature.getReturnType()), new TypeOfExpression(theTarget));
                    aHelper.push(theNewVariable);
                } else {
                    DirectInvokeMethodExpression theExpression = new DirectInvokeMethodExpression(theType, theMethodName, theSignature, theTarget, theArguments);
                    if (theSignature.getReturnType().isVoid()) {
                        aTargetBlock.getExpressions().add(theExpression);
                    } else {
                        Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theSignature.getReturnType()), theExpression);
                        aHelper.push(theNewVariable);
                    }
                }
            }
        } else if (theInstruction instanceof BytecodeInstructionINVOKEVIRTUAL) {
            BytecodeInstructionINVOKEVIRTUAL theINS = (BytecodeInstructionINVOKEVIRTUAL) theInstruction;
            BytecodeMethodSignature theSignature = theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
            if (theSignature.metchesExactlyTo(BytecodeLinkedClass.GET_CLASS_SIGNATURE) && "getClass".equals(theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue())) {
                Value theValue = new TypeOfExpression(aHelper.pop());
                Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theSignature.getReturnType()), theValue);
                aHelper.push(theNewVariable);
                continue;
            }
            List<Value> theArguments = new ArrayList<>();
            BytecodeTypeRef[] theArgumentTypes = theSignature.getArguments();
            for (BytecodeTypeRef theArgumentType : theArgumentTypes) {
                theArguments.add(aHelper.pop());
            }
            Collections.reverse(theArguments);
            Value theTarget = aHelper.pop();
            InvokeVirtualMethodExpression theExpression = new InvokeVirtualMethodExpression(theINS.getMethodReference().getNameAndTypeIndex().getNameAndType(), theTarget, theArguments);
            if (theSignature.getReturnType().isVoid()) {
                aTargetBlock.getExpressions().add(theExpression);
            } else {
                Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theSignature.getReturnType()), theExpression);
                aHelper.push(theNewVariable);
            }
        } else if (theInstruction instanceof BytecodeInstructionINVOKEINTERFACE) {
            BytecodeInstructionINVOKEINTERFACE theINS = (BytecodeInstructionINVOKEINTERFACE) theInstruction;
            BytecodeMethodSignature theSignature = theINS.getMethodDescriptor().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
            List<Value> theArguments = new ArrayList<>();
            BytecodeTypeRef[] theArgumentTypes = theSignature.getArguments();
            for (BytecodeTypeRef theArgumentType : theArgumentTypes) {
                theArguments.add(aHelper.pop());
            }
            Collections.reverse(theArguments);
            Value theTarget = aHelper.pop();
            InvokeVirtualMethodExpression theExpression = new InvokeVirtualMethodExpression(theINS.getMethodDescriptor().getNameAndTypeIndex().getNameAndType(), theTarget, theArguments);
            if (theSignature.getReturnType().isVoid()) {
                aTargetBlock.getExpressions().add(theExpression);
            } else {
                Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theSignature.getReturnType()), theExpression);
                aHelper.push(theNewVariable);
            }
        } else if (theInstruction instanceof BytecodeInstructionINVOKESTATIC) {
            BytecodeInstructionINVOKESTATIC theINS = (BytecodeInstructionINVOKESTATIC) theInstruction;
            BytecodeMethodSignature theSignature = theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
            List<Value> theArguments = new ArrayList<>();
            BytecodeTypeRef[] theArgumentTypes = theSignature.getArguments();
            for (BytecodeTypeRef theArgumentType : theArgumentTypes) {
                theArguments.add(aHelper.pop());
            }
            Collections.reverse(theArguments);
            BytecodeClassinfoConstant theTargetClass = theINS.getMethodReference().getClassIndex().getClassConstant();
            BytecodeObjectTypeRef theObjectType = BytecodeObjectTypeRef.fromUtf8Constant(theTargetClass.getConstant());
            if (Objects.equals(theObjectType.name(), MemoryManager.class.getName()) && "initTestMemory".equals(theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue())) {
            // This invocation can be skipped!!!
            } else if (Objects.equals(theObjectType.name(), Address.class.getName())) {
                String theMethodName = theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue();
                switch(theMethodName) {
                    case "setIntValue":
                        {
                            Value theTarget = theArguments.get(0);
                            Value theOffset = theArguments.get(1);
                            Value theNewValue = theArguments.get(2);
                            ComputedMemoryLocationWriteExpression theLocation = new ComputedMemoryLocationWriteExpression(theTarget, theOffset);
                            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT, theLocation);
                            aTargetBlock.getExpressions().add(new SetMemoryLocationExpression(theNewVariable, theNewValue));
                            break;
                        }
                    case "getStart":
                        {
                            Value theTarget = theArguments.get(0);
                            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT, theTarget);
                            aHelper.push(theNewVariable);
                            break;
                        }
                    case "getStackTop":
                        {
                            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT, new StackTopExpression());
                            aHelper.push(theNewVariable);
                            break;
                        }
                    case "getMemorySize":
                        {
                            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT, new MemorySizeExpression());
                            aHelper.push(theNewVariable);
                            break;
                        }
                    case "getIntValue":
                        {
                            Value theTarget = theArguments.get(0);
                            Value theOffset = theArguments.get(1);
                            ComputedMemoryLocationReadExpression theLocation = new ComputedMemoryLocationReadExpression(theTarget, theOffset);
                            Variable theNewVariable = aTargetBlock.newVariable(TypeRef.Native.INT, theLocation);
                            aHelper.push(theNewVariable);
                            break;
                        }
                    case "unreachable":
                        {
                            aTargetBlock.getExpressions().add(new UnreachableExpression());
                            break;
                        }
                    default:
                        throw new IllegalStateException("Not implemented : " + theMethodName);
                }
            } else {
                BytecodeObjectTypeRef theClassToInvoke = BytecodeObjectTypeRef.fromUtf8Constant(theINS.getMethodReference().getClassIndex().getClassConstant().getConstant());
                linkerContext.resolveClass(theClassToInvoke).resolveStaticMethod(theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue(), theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature());
                BytecodeMethodSignature theCalledSignature = theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
                if ("sqrt".equals(theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue()) && "java.lang.StrictMath".equals(theClassToInvoke.name())) {
                    Value theValue = new SqrtExpression(TypeRef.toType(theCalledSignature.getReturnType()), theArguments.get(0));
                    Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theSignature.getReturnType()), theValue);
                    aHelper.push(theNewVariable);
                } else if ("newInstance".equals(theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue()) && "java.lang.reflect.Array".equals(theClassToInvoke.name())) {
                    Value theArrayType = theArguments.get(0);
                    Value theArraySize = theArguments.get(1);
                    Value theValue = new NewArrayExpression(BytecodeObjectTypeRef.fromRuntimeClass(Object.class), theArraySize);
                    Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theSignature.getReturnType()), theValue);
                    aHelper.push(theNewVariable);
                } else {
                    InvokeStaticMethodExpression theExpression = new InvokeStaticMethodExpression(theClassToInvoke, theINS.getMethodReference().getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue(), theCalledSignature, theArguments);
                    if (theSignature.getReturnType().isVoid()) {
                        aTargetBlock.getExpressions().add(theExpression);
                    } else {
                        Variable theNewVariable = aTargetBlock.newVariable(TypeRef.toType(theSignature.getReturnType()), theExpression);
                        aHelper.push(theNewVariable);
                    }
                }
            }
        } else if (theInstruction instanceof BytecodeInstructionINSTANCEOF) {
            BytecodeInstructionINSTANCEOF theINS = (BytecodeInstructionINSTANCEOF) theInstruction;
            Value theValueToCheck = aHelper.pop();
            InstanceOfExpression theValue = new InstanceOfExpression(theValueToCheck, theINS.getTypeRef());
            Variable theCheckResult = aTargetBlock.newVariable(TypeRef.Native.BOOLEAN, theValue);
            aHelper.push(theCheckResult);
        } else if (theInstruction instanceof BytecodeInstructionTABLESWITCH) {
            BytecodeInstructionTABLESWITCH theINS = (BytecodeInstructionTABLESWITCH) theInstruction;
            Value theValue = aHelper.pop();
            ExpressionList theDefault = new ExpressionList();
            theDefault.add(new GotoExpression(theINS.getDefaultJumpTarget()));
            Map<Long, ExpressionList> theOffsets = new HashMap<>();
            long[] theJumpTargets = theINS.getOffsets();
            for (int i = 0; i < theJumpTargets.length; i++) {
                ExpressionList theJump = new ExpressionList();
                theJump.add(new GotoExpression(theINS.getOpcodeAddress().add((int) theJumpTargets[i])));
                theOffsets.put((long) i, theJump);
            }
            aTargetBlock.getExpressions().add(new TableSwitchExpression(theValue, theINS.getLowValue(), theINS.getHighValue(), theDefault, theOffsets));
        } else if (theInstruction instanceof BytecodeInstructionLOOKUPSWITCH) {
            BytecodeInstructionLOOKUPSWITCH theINS = (BytecodeInstructionLOOKUPSWITCH) theInstruction;
            Value theValue = aHelper.pop();
            ExpressionList theDefault = new ExpressionList();
            theDefault.add(new GotoExpression(theINS.getDefaultJumpTarget()));
            Map<Long, ExpressionList> thePairs = new HashMap<>();
            for (BytecodeInstructionLOOKUPSWITCH.Pair thePair : theINS.getPairs()) {
                ExpressionList thePairExpressions = new ExpressionList();
                thePairExpressions.add(new GotoExpression(theINS.getOpcodeAddress().add((int) thePair.getOffset())));
                thePairs.put(thePair.getMatch(), thePairExpressions);
            }
            aTargetBlock.getExpressions().add(new LookupSwitchExpression(theValue, theDefault, thePairs));
        } else if (theInstruction instanceof BytecodeInstructionINVOKEDYNAMIC) {
            BytecodeInstructionINVOKEDYNAMIC theINS = (BytecodeInstructionINVOKEDYNAMIC) theInstruction;
            BytecodeInvokeDynamicConstant theConstant = theINS.getCallSite();
            BytecodeMethodSignature theInitSignature = theConstant.getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
            BytecodeBootstrapMethodsAttributeInfo theBootStrapMethods = aOwningClass.getAttributes().getByType(BytecodeBootstrapMethodsAttributeInfo.class);
            BytecodeBootstrapMethod theBootstrapMethod = theBootStrapMethods.methodByIndex(theConstant.getBootstrapMethodAttributeIndex().getIndex());
            BytecodeMethodHandleConstant theMethodRef = theBootstrapMethod.getMethodRef();
            BytecodeMethodRefConstant theBootstrapMethodToInvoke = (BytecodeMethodRefConstant) theMethodRef.getReferenceIndex().getConstant();
            Program theProgram = new Program();
            RegionNode theInitNode = theProgram.getControlFlowGraph().createAt(BytecodeOpcodeAddress.START_AT_ZERO, RegionNode.BlockType.NORMAL);
            switch(theMethodRef.getReferenceKind()) {
                case REF_invokeStatic:
                    {
                        BytecodeObjectTypeRef theClassWithBootstrapMethod = BytecodeObjectTypeRef.fromUtf8Constant(theBootstrapMethodToInvoke.getClassIndex().getClassConstant().getConstant());
                        BytecodeMethodSignature theSignature = theBootstrapMethodToInvoke.getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature();
                        List<Value> theArguments = new ArrayList<>();
                        // Add the three default constants
                        // TMethodHandles.Lookup aCaller,
                        theArguments.add(theInitNode.newVariable(TypeRef.Native.REFERENCE, new MethodHandlesGeneratedLookupExpression(theClassWithBootstrapMethod)));
                        theArguments.add(theInitNode.newVariable(TypeRef.Native.REFERENCE, new StringValue(theConstant.getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue())));
                        // TMethodType aInvokedType,
                        theArguments.add(theInitNode.newVariable(TypeRef.Native.REFERENCE, new MethodTypeExpression(theInitSignature)));
                        // Revolve the static arguments
                        for (BytecodeConstant theArgumentConstant : theBootstrapMethod.getArguments()) {
                            if (theArgumentConstant instanceof BytecodeMethodTypeConstant) {
                                BytecodeMethodTypeConstant theMethodType = (BytecodeMethodTypeConstant) theArgumentConstant;
                                theArguments.add(theInitNode.newVariable(TypeRef.Native.REFERENCE, new MethodTypeExpression(theMethodType.getDescriptorIndex().methodSignature())));
                                continue;
                            }
                            if (theArgumentConstant instanceof BytecodeStringConstant) {
                                BytecodeStringConstant thePrimitive = (BytecodeStringConstant) theArgumentConstant;
                                theArguments.add(theInitNode.newVariable(TypeRef.Native.REFERENCE, new StringValue(thePrimitive.getValue().stringValue())));
                                continue;
                            }
                            if (theArgumentConstant instanceof BytecodeLongConstant) {
                                BytecodeLongConstant thePrimitive = (BytecodeLongConstant) theArgumentConstant;
                                theArguments.add(theInitNode.newVariable(TypeRef.Native.LONG, new LongValue(thePrimitive.getLongValue())));
                                continue;
                            }
                            if (theArgumentConstant instanceof BytecodeIntegerConstant) {
                                BytecodeIntegerConstant thePrimitive = (BytecodeIntegerConstant) theArgumentConstant;
                                theArguments.add(theInitNode.newVariable(TypeRef.Native.INT, new LongValue(thePrimitive.getIntegerValue())));
                                continue;
                            }
                            if (theArgumentConstant instanceof BytecodeFloatConstant) {
                                BytecodeFloatConstant thePrimitive = (BytecodeFloatConstant) theArgumentConstant;
                                theArguments.add(theInitNode.newVariable(TypeRef.Native.FLOAT, new FloatValue(thePrimitive.getFloatValue())));
                                continue;
                            }
                            if (theArgumentConstant instanceof BytecodeDoubleConstant) {
                                BytecodeDoubleConstant thePrimitive = (BytecodeDoubleConstant) theArgumentConstant;
                                theArguments.add(theInitNode.newVariable(TypeRef.Native.DOUBLE, new DoubleValue(thePrimitive.getDoubleValue())));
                                continue;
                            }
                            if (theArgumentConstant instanceof BytecodeMethodHandleConstant) {
                                BytecodeMethodHandleConstant theMethodHandle = (BytecodeMethodHandleConstant) theArgumentConstant;
                                BytecodeReferenceIndex theReference = theMethodHandle.getReferenceIndex();
                                BytecodeMethodRefConstant theReferenceConstant = (BytecodeMethodRefConstant) theReference.getConstant();
                                theArguments.add(theInitNode.newVariable(TypeRef.Native.REFERENCE, new MethodRefExpression(theReferenceConstant)));
                                continue;
                            }
                            throw new IllegalStateException("Unsupported argument type : " + theArgumentConstant);
                        }
                        // Ok, is the last argument of the bootstrap method a vararg argument
                        BytecodeTypeRef theLastArgument = theSignature.getArguments()[theSignature.getArguments().length - 1];
                        if (theLastArgument.isArray()) {
                            // Yes, so we have to wrap everything from this position on in an array
                            int theSignatureLength = theSignature.getArguments().length;
                            int theArgumentsLength = theArguments.size();
                            int theVarArgsLength = theArgumentsLength - theSignatureLength + 1;
                            Variable theNewVarargsArray = theInitNode.newVariable(TypeRef.Native.REFERENCE, new NewArrayExpression(BytecodeObjectTypeRef.fromRuntimeClass(Object.class), new IntegerValue(theVarArgsLength)));
                            for (int i = theSignatureLength - 1; i < theArgumentsLength; i++) {
                                Value theVariable = theArguments.get(i);
                                theArguments.remove(theVariable);
                                theInitNode.getExpressions().add(new ArrayStoreExpression(TypeRef.Native.REFERENCE, theNewVarargsArray, new IntegerValue(i - theSignatureLength + 1), theVariable));
                            }
                            theArguments.add(theNewVarargsArray);
                        }
                        InvokeStaticMethodExpression theInvokeStaticValue = new InvokeStaticMethodExpression(BytecodeObjectTypeRef.fromUtf8Constant(theBootstrapMethodToInvoke.getClassIndex().getClassConstant().getConstant()), theBootstrapMethodToInvoke.getNameAndTypeIndex().getNameAndType().getNameIndex().getName().stringValue(), theBootstrapMethodToInvoke.getNameAndTypeIndex().getNameAndType().getDescriptorIndex().methodSignature(), theArguments);
                        Variable theNewVariable = theInitNode.newVariable(TypeRef.Native.REFERENCE, theInvokeStaticValue);
                        theInitNode.getExpressions().add(new ReturnValueExpression(theNewVariable));
                        // First step, we construct a callsite
                        ResolveCallsiteObjectExpression theValue = new ResolveCallsiteObjectExpression(aOwningClass.getThisInfo().getConstant().stringValue() + "_" + aMethod.getName().stringValue() + "_" + theINS.getOpcodeAddress().getAddress(), aOwningClass, theProgram, theInitNode);
                        Variable theCallsiteVariable = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, theValue);
                        List<Value> theInvokeArguments = new ArrayList<>();
                        Variable theArray = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, new NewArrayExpression(BytecodeObjectTypeRef.fromRuntimeClass(Object.class), new IntegerValue(theInitSignature.getArguments().length)));
                        for (int i = theInitSignature.getArguments().length - 1; i >= 0; i--) {
                            Value theIndex = new IntegerValue(i);
                            Value theStoredValue = aHelper.pop();
                            if (theStoredValue.resolveType() == TypeRef.Native.INT) {
                                // Create Integer object to contain int
                                BytecodeObjectTypeRef theType = BytecodeObjectTypeRef.fromRuntimeClass(Integer.class);
                                BytecodeTypeRef[] args_def = new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT };
                                BytecodeMethodSignature sig = new BytecodeMethodSignature(theType, args_def);
                                List<Value> args = new ArrayList<>();
                                args.add(theStoredValue);
                                theStoredValue = new InvokeStaticMethodExpression(theType, "valueOf", sig, args);
                                theStoredValue = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, theStoredValue);
                            }
                            aTargetBlock.getExpressions().add(new ArrayStoreExpression(TypeRef.Native.REFERENCE, theArray, theIndex, theStoredValue));
                        }
                        theInvokeArguments.add(theArray);
                        InvokeVirtualMethodExpression theInvokeValue = new InvokeVirtualMethodExpression("invokeExact", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Object.class), new BytecodeTypeRef[] { new BytecodeArrayTypeRef(BytecodeObjectTypeRef.fromRuntimeClass(Object.class), 1) }), theCallsiteVariable, theInvokeArguments);
                        Variable theInvokeExactResult = aTargetBlock.newVariable(TypeRef.Native.REFERENCE, theInvokeValue);
                        aHelper.push(theInvokeExactResult);
                        break;
                    }
                default:
                    throw new IllegalStateException("Nut supported reference kind for invoke dynamic : " + theMethodRef.getReferenceKind());
            }
        } else {
            throw new IllegalArgumentException("Not implemented : " + theInstruction);
        }
    }
    aHelper.finalizeExportState();
}
Also used : BytecodeInstructionGenericArraySTORE(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericArraySTORE) BytecodeInstructionFCONST(de.mirkosertic.bytecoder.core.BytecodeInstructionFCONST) BytecodeInstructionINVOKEDYNAMIC(de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKEDYNAMIC) BytecodeReferenceIndex(de.mirkosertic.bytecoder.core.BytecodeReferenceIndex) Address(de.mirkosertic.bytecoder.classlib.Address) BytecodeOpcodeAddress(de.mirkosertic.bytecoder.core.BytecodeOpcodeAddress) BytecodeInstructionATHROW(de.mirkosertic.bytecoder.core.BytecodeInstructionATHROW) ArrayList(java.util.ArrayList) BytecodeInstructionASTORE(de.mirkosertic.bytecoder.core.BytecodeInstructionASTORE) BytecodeInstructionDUP2X1(de.mirkosertic.bytecoder.core.BytecodeInstructionDUP2X1) BytecodeBasicBlock(de.mirkosertic.bytecoder.core.BytecodeBasicBlock) BytecodeInstructionGenericREM(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericREM) BytecodeInstructionGenericOR(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericOR) BytecodeInstructionF2Generic(de.mirkosertic.bytecoder.core.BytecodeInstructionF2Generic) BytecodeInstructionGenericSTORE(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericSTORE) BytecodeInstructionGenericDIV(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericDIV) BytecodeInstructionNOP(de.mirkosertic.bytecoder.core.BytecodeInstructionNOP) BytecodeInstructionGenericNEG(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericNEG) BytecodeInstructionGenericLOAD(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericLOAD) BytecodeInstructionIFICMP(de.mirkosertic.bytecoder.core.BytecodeInstructionIFICMP) BytecodeInstruction(de.mirkosertic.bytecoder.core.BytecodeInstruction) BytecodeInstructionIFACMP(de.mirkosertic.bytecoder.core.BytecodeInstructionIFACMP) BytecodeIntegerConstant(de.mirkosertic.bytecoder.core.BytecodeIntegerConstant) BytecodeInstructionGenericADD(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericADD) BytecodeInstructionCHECKCAST(de.mirkosertic.bytecoder.core.BytecodeInstructionCHECKCAST) BytecodeInstructionGETFIELD(de.mirkosertic.bytecoder.core.BytecodeInstructionGETFIELD) BytecodeTypeRef(de.mirkosertic.bytecoder.core.BytecodeTypeRef) BytecodeInstructionGenericSHR(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericSHR) BytecodeInstructionDCONST(de.mirkosertic.bytecoder.core.BytecodeInstructionDCONST) BytecodeInstructionGenericSHL(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericSHL) BytecodeInstructionINVOKESPECIAL(de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKESPECIAL) Map(java.util.Map) HashMap(java.util.HashMap) BytecodeInstructionICONST(de.mirkosertic.bytecoder.core.BytecodeInstructionICONST) BytecodeInstructionIFCOND(de.mirkosertic.bytecoder.core.BytecodeInstructionIFCOND) BytecodeInstructionNEWARRAY(de.mirkosertic.bytecoder.core.BytecodeInstructionNEWARRAY) BytecodeBootstrapMethodsAttributeInfo(de.mirkosertic.bytecoder.core.BytecodeBootstrapMethodsAttributeInfo) BytecodeInstructionGenericRETURN(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericRETURN) BytecodeInstructionGenericCMP(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericCMP) BytecodeInstructionI2Generic(de.mirkosertic.bytecoder.core.BytecodeInstructionI2Generic) BytecodeInstructionINVOKEINTERFACE(de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKEINTERFACE) BytecodeInstructionGOTO(de.mirkosertic.bytecoder.core.BytecodeInstructionGOTO) BytecodeInstructionARRAYLENGTH(de.mirkosertic.bytecoder.core.BytecodeInstructionARRAYLENGTH) BytecodeInstructionNEWMULTIARRAY(de.mirkosertic.bytecoder.core.BytecodeInstructionNEWMULTIARRAY) BytecodeInstructionLCMP(de.mirkosertic.bytecoder.core.BytecodeInstructionLCMP) BytecodeInstructionGenericSUB(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericSUB) BytecodeInstructionACONSTNULL(de.mirkosertic.bytecoder.core.BytecodeInstructionACONSTNULL) BytecodeInstructionSIPUSH(de.mirkosertic.bytecoder.core.BytecodeInstructionSIPUSH) BytecodeInstructionGenericXOR(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericXOR) BytecodeInstructionPUTSTATIC(de.mirkosertic.bytecoder.core.BytecodeInstructionPUTSTATIC) BytecodeInstructionRETURN(de.mirkosertic.bytecoder.core.BytecodeInstructionRETURN) BytecodeInstructionIFNONNULL(de.mirkosertic.bytecoder.core.BytecodeInstructionIFNONNULL) BytecodeInstructionNEW(de.mirkosertic.bytecoder.core.BytecodeInstructionNEW) BytecodeDoubleConstant(de.mirkosertic.bytecoder.core.BytecodeDoubleConstant) BytecodeStringConstant(de.mirkosertic.bytecoder.core.BytecodeStringConstant) BytecodeObjectTypeRef(de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef) BytecodeInstructionPUTFIELD(de.mirkosertic.bytecoder.core.BytecodeInstructionPUTFIELD) BytecodeInstructionLCONST(de.mirkosertic.bytecoder.core.BytecodeInstructionLCONST) BytecodeMethodSignature(de.mirkosertic.bytecoder.core.BytecodeMethodSignature) BytecodeInstructionPOP2(de.mirkosertic.bytecoder.core.BytecodeInstructionPOP2) HashMap(java.util.HashMap) BytecodeArrayTypeRef(de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef) BytecodeObjectTypeRef(de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef) BytecodePrimitiveTypeRef(de.mirkosertic.bytecoder.core.BytecodePrimitiveTypeRef) BytecodeTypeRef(de.mirkosertic.bytecoder.core.BytecodeTypeRef) BytecodeInstructionL2Generic(de.mirkosertic.bytecoder.core.BytecodeInstructionL2Generic) BytecodeInstructionMONITOREXIT(de.mirkosertic.bytecoder.core.BytecodeInstructionMONITOREXIT) BytecodeInstructionPOP(de.mirkosertic.bytecoder.core.BytecodeInstructionPOP) BytecodeInstructionDUPX2(de.mirkosertic.bytecoder.core.BytecodeInstructionDUPX2) BytecodeFloatConstant(de.mirkosertic.bytecoder.core.BytecodeFloatConstant) ArrayList(java.util.ArrayList) List(java.util.List) BytecodeMethodRefConstant(de.mirkosertic.bytecoder.core.BytecodeMethodRefConstant) BytecodeInstructionANEWARRAY(de.mirkosertic.bytecoder.core.BytecodeInstructionANEWARRAY) BytecodeInstructionObjectArrayLOAD(de.mirkosertic.bytecoder.core.BytecodeInstructionObjectArrayLOAD) BytecodeProgram(de.mirkosertic.bytecoder.core.BytecodeProgram) BytecodeInstructionDUPX1(de.mirkosertic.bytecoder.core.BytecodeInstructionDUPX1) BytecodeInstructionObjectArraySTORE(de.mirkosertic.bytecoder.core.BytecodeInstructionObjectArraySTORE) BytecodeInstructionD2Generic(de.mirkosertic.bytecoder.core.BytecodeInstructionD2Generic) BytecodeInstructionINSTANCEOF(de.mirkosertic.bytecoder.core.BytecodeInstructionINSTANCEOF) BytecodeLongConstant(de.mirkosertic.bytecoder.core.BytecodeLongConstant) BytecodeInstructionTABLESWITCH(de.mirkosertic.bytecoder.core.BytecodeInstructionTABLESWITCH) BytecodeInstructionDUP2(de.mirkosertic.bytecoder.core.BytecodeInstructionDUP2) BytecodeArrayTypeRef(de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef) VM(de.mirkosertic.bytecoder.classlib.VM) BytecodeConstant(de.mirkosertic.bytecoder.core.BytecodeConstant) BytecodeInstructionALOAD(de.mirkosertic.bytecoder.core.BytecodeInstructionALOAD) BytecodeInstructionGenericArrayLOAD(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericArrayLOAD) BytecodeInstructionINVOKESTATIC(de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKESTATIC) BytecodeInstructionGenericMUL(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericMUL) BytecodeInstructionDUP(de.mirkosertic.bytecoder.core.BytecodeInstructionDUP) BytecodeInstructionIINC(de.mirkosertic.bytecoder.core.BytecodeInstructionIINC) BytecodeInstructionGETSTATIC(de.mirkosertic.bytecoder.core.BytecodeInstructionGETSTATIC) BytecodeInstructionGenericAND(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericAND) BytecodeInstructionObjectRETURN(de.mirkosertic.bytecoder.core.BytecodeInstructionObjectRETURN) BytecodeInvokeDynamicConstant(de.mirkosertic.bytecoder.core.BytecodeInvokeDynamicConstant) BytecodeClassinfoConstant(de.mirkosertic.bytecoder.core.BytecodeClassinfoConstant) BytecodeInstructionGenericLDC(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericLDC) BytecodeInstructionIFNULL(de.mirkosertic.bytecoder.core.BytecodeInstructionIFNULL) BytecodeArrayTypeRef(de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef) BytecodeInstructionGenericUSHR(de.mirkosertic.bytecoder.core.BytecodeInstructionGenericUSHR) BytecodeMethodTypeConstant(de.mirkosertic.bytecoder.core.BytecodeMethodTypeConstant) BytecodeInstructionINVOKEVIRTUAL(de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKEVIRTUAL) BytecodeBootstrapMethod(de.mirkosertic.bytecoder.core.BytecodeBootstrapMethod) BytecodeInstructionBIPUSH(de.mirkosertic.bytecoder.core.BytecodeInstructionBIPUSH) Array(java.lang.reflect.Array) BytecodeUtf8Constant(de.mirkosertic.bytecoder.core.BytecodeUtf8Constant) BytecodeInstructionMONITORENTER(de.mirkosertic.bytecoder.core.BytecodeInstructionMONITORENTER) BytecodeMethodHandleConstant(de.mirkosertic.bytecoder.core.BytecodeMethodHandleConstant) BytecodeInstructionLOOKUPSWITCH(de.mirkosertic.bytecoder.core.BytecodeInstructionLOOKUPSWITCH)

Example 3 with BytecodeArrayTypeRef

use of de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef in project Bytecoder by mirkosertic.

the class JSSSACompilerBackend method generateCodeFor.

@Override
public JSCompileResult generateCodeFor(CompileOptions aOptions, BytecodeLinkerContext aLinkerContext, Class aEntryPointClass, String aEntryPointMethodName, BytecodeMethodSignature aEntryPointSignatue) {
    BytecodeLinkedClass theExceptionRethrower = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(ExceptionRethrower.class));
    theExceptionRethrower.resolveStaticMethod("registerExceptionOutcome", registerExceptionOutcomeSignature);
    theExceptionRethrower.resolveStaticMethod("getLastOutcomeOrNullAndReset", getLastExceptionOutcomeSignature);
    StringWriter theStrWriter = new StringWriter();
    PrintWriter theWriter = new PrintWriter(theStrWriter);
    theWriter.println("'use strict';");
    theWriter.println();
    theWriter.println("var bytecoderGlobalMemory = [];");
    theWriter.println();
    theWriter.println("var bytecoder = {");
    theWriter.println();
    theWriter.println("     logDebug : function(aValue) { ");
    theWriter.println("         console.log(aValue);");
    theWriter.println("     }, ");
    theWriter.println();
    theWriter.println("     logByteArrayAsString : function(aArray) { ");
    theWriter.println("         var theResult = '';");
    theWriter.println("         for (var i=0;i<aArray.data.length;i++) {");
    theWriter.println("             theResult += String.fromCharCode(aArray.data[i]);");
    theWriter.println("         }");
    theWriter.println("         console.log(theResult);");
    theWriter.println("     }, ");
    theWriter.println();
    theWriter.println("     newString : function(aByteArray) { ");
    BytecodeObjectTypeRef theStringTypeRef = BytecodeObjectTypeRef.fromRuntimeClass(String.class);
    BytecodeObjectTypeRef theArrayTypeRef = BytecodeObjectTypeRef.fromRuntimeClass(Array.class);
    BytecodeMethodSignature theStringConstructorSignature = new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[] { new BytecodeArrayTypeRef(BytecodePrimitiveTypeRef.BYTE, 1) });
    // Construct a String
    theWriter.println("          var theNewString = new " + JSWriterUtils.toClassName(theStringTypeRef) + ".Create();");
    theWriter.println("          var theBytes = new " + JSWriterUtils.toClassName(theArrayTypeRef) + ".Create();");
    theWriter.println("          theBytes.data = aByteArray;");
    theWriter.println("          " + JSWriterUtils.toClassName(theStringTypeRef) + '.' + JSWriterUtils.toMethodName("init", theStringConstructorSignature) + "(theNewString, theBytes);");
    theWriter.println("          return theNewString;");
    theWriter.println("     },");
    theWriter.println();
    theWriter.println("     newMultiArray : function(aDimensions, aDefault) {");
    theWriter.println("         var theLength = aDimensions[0];");
    theWriter.println("         var theArray = bytecoder.newArray(theLength, aDefault);");
    theWriter.println("         if (aDimensions.length > 1) {");
    theWriter.println("             var theNewDimensions = aDimensions.slice(0);");
    theWriter.println("             theNewDimensions.shift();");
    theWriter.println("             for (var i=0;i<theLength;i++) {");
    theWriter.println("                 theArray.data[i] = bytecoder.newMultiArray(theNewDimensions, aDefault);");
    theWriter.println("             }");
    theWriter.println("         }");
    theWriter.println("         return theArray;");
    theWriter.println("     },");
    theWriter.println();
    theWriter.println("     newArray : function(aLength, aDefault) {");
    BytecodeObjectTypeRef theArrayType = BytecodeObjectTypeRef.fromRuntimeClass(Array.class);
    theWriter.println("          var theInstance = new " + JSWriterUtils.toClassName(theArrayType) + ".Create();");
    theWriter.println("          theInstance.data = [];");
    theWriter.println("          theInstance.data.length = aLength;");
    theWriter.println("          for (var i=0;i<aLength;i++) {");
    theWriter.println("             theInstance.data[i] = aDefault;");
    theWriter.println("          }");
    theWriter.println("          return theInstance;");
    theWriter.println("     },");
    theWriter.println();
    theWriter.println("     dynamicType : function(aFunction) { ");
    theWriter.println("         return new Proxy({}, {");
    theWriter.println("             get: function(target, name) {");
    theWriter.println("                 return function(inst, _p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9) {");
    theWriter.println("                    return aFunction(_p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8, _p9);");
    theWriter.println("                 }");
    theWriter.println("             }");
    theWriter.println("         });");
    theWriter.println("     }, ");
    theWriter.println();
    theWriter.println("     resolveStaticCallSiteObject: function(aWhere, aKey, aProducerFunction) {");
    theWriter.println("         var resolvedCallsiteObject = aWhere.__staticCallSites[aKey];");
    theWriter.println("         if (resolvedCallsiteObject == null) {");
    theWriter.println("             resolvedCallsiteObject = aProducerFunction();");
    theWriter.println("             aWhere.__staticCallSites[aKey] = resolvedCallsiteObject;");
    theWriter.println("         }");
    theWriter.println("         return resolvedCallsiteObject;");
    theWriter.println("     },");
    theWriter.println();
    theWriter.println("     imports : [],");
    theWriter.println();
    theWriter.println("     stringpool : [],");
    theWriter.println();
    theWriter.println("};");
    theWriter.println();
    ConstantPool thePool = new ConstantPool();
    aLinkerContext.linkedClasses().forEach(theEntry -> {
        BytecodeLinkedClass theLinkedClass = theEntry.targetNode();
        // Here we collect everything that is required for class initialization
        // this includes the super class, all implementing interfaces and also static
        // dependencies of the class initialization code
        List<BytecodeObjectTypeRef> theInitDependencies = new ArrayList<>();
        BytecodeLinkedClass theSuperClass = theLinkedClass.getSuperClass();
        if (theSuperClass != null) {
            theInitDependencies.add(theSuperClass.getClassName());
        }
        for (BytecodeLinkedClass theInterface : theLinkedClass.getImplementingTypes()) {
            if (!theInitDependencies.contains(theInterface.getClassName())) {
                theInitDependencies.add(theInterface.getClassName());
            }
        }
        BytecodeResolvedMethods theMethods = theLinkedClass.resolvedMethods();
        String theJSClassName = JSWriterUtils.toClassName(theEntry.edgeType().objectTypeRef());
        theWriter.println("var " + theJSClassName + " = {");
        // First of all, we add static fields required by the framework
        theWriter.println("    __initialized : false,");
        theWriter.println("    __staticCallSites : [],");
        theWriter.print("    __typeId : ");
        theWriter.print(theLinkedClass.getUniqueId());
        theWriter.println(",");
        theWriter.print("    __implementedTypes : [");
        {
            boolean first = true;
            for (BytecodeLinkedClass theType : theLinkedClass.getImplementingTypes()) {
                if (!first) {
                    theWriter.print(",");
                }
                first = false;
                theWriter.print(theType.getUniqueId());
            }
        }
        theWriter.println("],");
        // then we add class specific static fields
        BytecodeResolvedFields theStaticFields = theLinkedClass.resolvedFields();
        theStaticFields.streamForStaticFields().forEach(aFieldEntry -> {
            BytecodeTypeRef theFieldType = aFieldEntry.getValue().getTypeRef();
            if (theFieldType.isPrimitive()) {
                BytecodePrimitiveTypeRef thePrimitive = (BytecodePrimitiveTypeRef) theFieldType;
                switch(thePrimitive) {
                    case BOOLEAN:
                        {
                            theWriter.print("    ");
                            theWriter.print(aFieldEntry.getValue().getName().stringValue());
                            theWriter.print(" : false, // declared in ");
                            theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
                            break;
                        }
                    default:
                        {
                            theWriter.print("    ");
                            theWriter.print(aFieldEntry.getValue().getName().stringValue());
                            theWriter.print(" : 0, // declared in ");
                            theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
                            break;
                        }
                }
            } else {
                theWriter.print("    ");
                theWriter.print(aFieldEntry.getValue().getName().stringValue());
                theWriter.print(" : null, // declared in ");
                theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
            }
        });
        theWriter.println();
        if (!theLinkedClass.getBytecodeClass().getAccessFlags().isAbstract()) {
            // The Constructor function initializes all object members with null
            // Only non abstract classes can be instantiated
            BytecodeResolvedFields theInstanceFields = theLinkedClass.resolvedFields();
            theWriter.println("    Create : function() {");
            theInstanceFields.streamForInstanceFields().forEach(aFieldEntry -> {
                BytecodeTypeRef theFieldType = aFieldEntry.getValue().getTypeRef();
                if (theFieldType.isPrimitive()) {
                    BytecodePrimitiveTypeRef thePrimitive = (BytecodePrimitiveTypeRef) theFieldType;
                    switch(thePrimitive) {
                        case BOOLEAN:
                            {
                                theWriter.print("        this.");
                                theWriter.print(aFieldEntry.getValue().getName().stringValue());
                                theWriter.print(" = false; // declared in ");
                                theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
                                break;
                            }
                        default:
                            {
                                theWriter.print("        this.");
                                theWriter.print(aFieldEntry.getValue().getName().stringValue());
                                theWriter.print(" = 0; // declared in ");
                                theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
                                break;
                            }
                    }
                } else {
                    theWriter.print("        this.");
                    theWriter.print(aFieldEntry.getValue().getName().stringValue());
                    theWriter.print(" = null; // declared in ");
                    theWriter.println(aFieldEntry.getProvidingClass().getClassName().name());
                }
            });
            theWriter.println("    },");
            theWriter.println();
        }
        if (!theLinkedClass.getBytecodeClass().getAccessFlags().isInterface()) {
            theWriter.println("    instanceOf : function(aType) {");
            theWriter.print("        return ");
            theWriter.print(theJSClassName);
            theWriter.println(".__implementedTypes.includes(aType.__typeId);");
            theWriter.println("    },");
            theWriter.println();
            theWriter.println("    ClassgetClass : function() {");
            theWriter.print("        return ");
            theWriter.print(theJSClassName);
            theWriter.println(";");
            theWriter.println("    },");
            theWriter.println();
            theWriter.println("    BOOLEANdesiredAssertionStatus : function() {");
            theWriter.println("        return false;");
            theWriter.println("    },");
            theWriter.println();
            theWriter.println("    A1jlObjectgetEnumConstants : function(aClazz) {");
            theWriter.println("        return aClazz.$VALUES;");
            theWriter.println("    },");
        }
        theMethods.stream().forEach(aEntry -> {
            BytecodeMethod theMethod = aEntry.getValue();
            BytecodeMethodSignature theCurrentMethodSignature = 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 (!(aEntry.getProvidingClass() == theLinkedClass)) {
                // But include static methods, as they are inherited from the base classes
                if (aEntry.getValue().getAccessFlags().isStatic() && !aEntry.getValue().isClassInitializer()) {
                    StringBuilder theArguments = new StringBuilder();
                    ;
                    for (int i = 0; i < theCurrentMethodSignature.getArguments().length; i++) {
                        if (i > 0) {
                            theArguments.append(',');
                        }
                        theArguments.append('p');
                        theArguments.append(i);
                    }
                    // Static methods will just delegate to the implementation in the class
                    theWriter.println();
                    theWriter.println("    " + JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature) + " : function(" + theArguments + ") {");
                    if (!theCurrentMethodSignature.getReturnType().isVoid()) {
                        theWriter.print("         return ");
                    } else {
                        theWriter.print("         ");
                    }
                    theWriter.print(JSWriterUtils.toClassName(aEntry.getProvidingClass().getClassName()));
                    theWriter.print(".");
                    theWriter.print(JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature));
                    theWriter.print("(");
                    theWriter.print(theArguments);
                    theWriter.println(");");
                    theWriter.println("    },");
                }
                return;
            }
            aLinkerContext.getLogger().info("Compiling {}.{}", theLinkedClass.getClassName().name(), theMethod.getName().stringValue());
            ProgramGenerator theGenerator = programGeneratorFactory.createFor(aLinkerContext);
            Program theSSAProgram = theGenerator.generateFrom(aEntry.getProvidingClass().getBytecodeClass(), theMethod);
            // Run optimizer
            aOptions.getOptimizer().optimize(theSSAProgram.getControlFlowGraph(), aLinkerContext);
            StringBuilder theArguments = new StringBuilder();
            for (Program.Argument theArgument : theSSAProgram.getArguments()) {
                if (theArguments.length() > 0) {
                    theArguments.append(',');
                }
                theArguments.append(theArgument.getVariable().getName());
            }
            if (theMethod.getAccessFlags().isNative()) {
                if (theLinkedClass.getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
                    return;
                }
                BytecodeImportedLink theLink = theLinkedClass.linkfor(theMethod);
                theWriter.println();
                theWriter.println("    " + JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature) + " : function(" + theArguments + ") {");
                theWriter.print("         return bytecoder.imports.");
                theWriter.print(theLink.getModuleName());
                theWriter.print(".");
                theWriter.print(theLink.getLinkName());
                theWriter.print("(");
                theWriter.print(theArguments);
                theWriter.println(");");
                theWriter.println("    },");
                return;
            }
            theWriter.println();
            theWriter.println("    " + JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theCurrentMethodSignature) + " : function(" + theArguments + ") {");
            if (Objects.equals(theMethod.getName().stringValue(), "<clinit>")) {
                for (BytecodeObjectTypeRef theRef : theSSAProgram.getStaticReferences()) {
                    if (!theInitDependencies.contains(theRef)) {
                        theInitDependencies.add(theRef);
                    }
                }
            }
            if (aOptions.isDebugOutput()) {
                theWriter.println("        /**");
                theWriter.println("        " + theSSAProgram.getControlFlowGraph().toDOT());
                theWriter.println("        */");
            }
            JSSSAWriter theVariablesWriter = new JSSSAWriter(aOptions, theSSAProgram, "        ", theWriter, aLinkerContext, thePool);
            for (Variable theVariable : theSSAProgram.globalVariables()) {
                if (!theVariable.isSynthetic()) {
                    theVariablesWriter.print("var ");
                    theVariablesWriter.print(theVariable.getName());
                    theVariablesWriter.print(" = null;");
                    theVariablesWriter.print(" // type is ");
                    theVariablesWriter.print(theVariable.resolveType().resolve().name());
                    theVariablesWriter.print(" # of inits = " + theVariable.incomingDataFlows().size());
                    theVariablesWriter.println();
                }
            }
            // Try to reloop it!
            try {
                Relooper theRelooper = new Relooper();
                Relooper.Block theReloopedBlock = theRelooper.reloop(theSSAProgram.getControlFlowGraph());
                theVariablesWriter.printRelooped(theReloopedBlock);
            } catch (Exception e) {
                System.out.println(theSSAProgram.getControlFlowGraph().toDOT());
                throw new IllegalStateException("Error relooping cfg for " + theLinkedClass.getClassName().name() + '.' + theMethod.getName().stringValue(), e);
            }
            theWriter.println("    },");
        });
        theWriter.println();
        theWriter.println("    classInitCheck : function() {");
        theWriter.println("        if (!" + theJSClassName + ".__initialized) {");
        theWriter.println("            " + theJSClassName + ".__initialized = true;");
        if (!theLinkedClass.getBytecodeClass().getAccessFlags().isAbstract()) {
            // Now we have to setup the prototype
            // Only in case this class can be instantiated of course
            theWriter.println("            var thePrototype = " + theJSClassName + ".Create.prototype;");
            theWriter.println("            thePrototype.instanceOf = " + theJSClassName + ".instanceOf;");
            theWriter.println("            thePrototype.ClassgetClass = " + theJSClassName + ".ClassgetClass;");
            List<BytecodeResolvedMethods.MethodEntry> theEntries = theMethods.stream().collect(Collectors.toList());
            Set<String> theVisitedMethods = new HashSet<>();
            for (int i = theEntries.size() - 1; i >= 0; i--) {
                BytecodeResolvedMethods.MethodEntry aEntry = theEntries.get(i);
                BytecodeMethod theMethod = aEntry.getValue();
                String theMethodName = JSWriterUtils.toMethodName(theMethod.getName().stringValue(), theMethod.getSignature());
                if (!theMethod.getAccessFlags().isStatic() && !theMethod.getAccessFlags().isAbstract() && !theMethod.isConstructor() && !theMethod.isClassInitializer()) {
                    if (theVisitedMethods.add(theMethodName)) {
                        theWriter.print("            thePrototype.");
                        theWriter.print(theMethodName);
                        theWriter.print(" = ");
                        theWriter.print(JSWriterUtils.toClassName(aEntry.getProvidingClass().getClassName()));
                        theWriter.print(".");
                        theWriter.print(theMethodName);
                        theWriter.println(";");
                    }
                }
            }
        }
        for (BytecodeObjectTypeRef theRef : theInitDependencies) {
            if (!Objects.equals(theRef, theEntry.edgeType().objectTypeRef())) {
                theWriter.print("            ");
                theWriter.print(JSWriterUtils.toClassName(theRef));
                theWriter.println(".classInitCheck();");
            }
        }
        if (theLinkedClass.hasClassInitializer()) {
            theWriter.println("            " + theJSClassName + ".VOIDclinit();");
        }
        theWriter.println("        }");
        theWriter.println("    },");
        theWriter.println();
        theWriter.println("};");
        theWriter.println();
    });
    theWriter.println();
    theWriter.println("bytecoder.bootstrap = function() {");
    List<StringValue> theValues = thePool.stringValues();
    for (int i = 0; i < theValues.size(); i++) {
        StringValue theValue = theValues.get(i);
        theWriter.print("    bytecoder.stringpool[");
        theWriter.print(i);
        theWriter.print("] = bytecoder.newString(");
        theWriter.print(JSWriterUtils.toArray(theValue.getStringValue().getBytes()));
        theWriter.println(");");
    }
    aLinkerContext.linkedClasses().forEach(aEntry -> {
        if (!aEntry.targetNode().getBytecodeClass().getAccessFlags().isInterface()) {
            theWriter.print("    ");
            theWriter.print(JSWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
            theWriter.println(".classInitCheck();");
        }
    });
    theWriter.println("}");
    theWriter.flush();
    return new JSCompileResult(theStrWriter.toString());
}
Also used : Variable(de.mirkosertic.bytecoder.ssa.Variable) BytecodeMethodSignature(de.mirkosertic.bytecoder.core.BytecodeMethodSignature) ArrayList(java.util.ArrayList) BytecodeMethod(de.mirkosertic.bytecoder.core.BytecodeMethod) ProgramGenerator(de.mirkosertic.bytecoder.ssa.ProgramGenerator) BytecodeResolvedMethods(de.mirkosertic.bytecoder.core.BytecodeResolvedMethods) StringWriter(java.io.StringWriter) BytecodeLinkedClass(de.mirkosertic.bytecoder.core.BytecodeLinkedClass) StringValue(de.mirkosertic.bytecoder.ssa.StringValue) BytecodeResolvedFields(de.mirkosertic.bytecoder.core.BytecodeResolvedFields) PrintWriter(java.io.PrintWriter) HashSet(java.util.HashSet) BytecodeProgram(de.mirkosertic.bytecoder.core.BytecodeProgram) Program(de.mirkosertic.bytecoder.ssa.Program) BytecodePrimitiveTypeRef(de.mirkosertic.bytecoder.core.BytecodePrimitiveTypeRef) BytecodeTypeRef(de.mirkosertic.bytecoder.core.BytecodeTypeRef) BytecodeObjectTypeRef(de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef) Relooper(de.mirkosertic.bytecoder.relooper.Relooper) BytecodeArrayTypeRef(de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef) ConstantPool(de.mirkosertic.bytecoder.backend.ConstantPool) BytecodeImportedLink(de.mirkosertic.bytecoder.core.BytecodeImportedLink) ExceptionRethrower(de.mirkosertic.bytecoder.classlib.ExceptionRethrower)

Example 4 with BytecodeArrayTypeRef

use of de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef 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 5 with BytecodeArrayTypeRef

use of de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef in project Bytecoder by mirkosertic.

the class CompileTarget method compileToJS.

public CompileResult compileToJS(CompileOptions aOptions, Class aClass, String aMethodName, BytecodeMethodSignature aSignature) {
    BytecodeLinkerContext theLinkerContext = new BytecodeLinkerContext(bytecodeLoader, aOptions.getLogger());
    BytecodeLinkedClass theClassLinkedCass = theLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(Class.class));
    theClassLinkedCass.resolveConstructorInvocation(new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[] {}));
    // Lambda handling
    BytecodeLinkedClass theCallsite = theLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(VM.ImplementingCallsite.class));
    theCallsite.resolveVirtualMethod("invokeExact", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Object.class), new BytecodeTypeRef[] { new BytecodeArrayTypeRef(BytecodeObjectTypeRef.fromRuntimeClass(Object.class), 1) }));
    BytecodeObjectTypeRef theTypeRef = BytecodeObjectTypeRef.fromRuntimeClass(aClass);
    BytecodeLinkedClass theClass = theLinkerContext.resolveClass(theTypeRef);
    BytecodeMethod theMethod = theClass.getBytecodeClass().methodByNameAndSignatureOrNull(aMethodName, aSignature);
    if (theMethod.getAccessFlags().isStatic()) {
        theClass.resolveStaticMethod(aMethodName, aSignature);
    } else {
        theClass.resolveVirtualMethod(aMethodName, aSignature);
    }
    // Before code generation we have to make sure that all abstract method implementations are linked correctly
    aOptions.getLogger().info("Resolving abstract method hierarchy");
    theLinkerContext.resolveAbstractMethodsInSubclasses();
    return backend.generateCodeFor(aOptions, theLinkerContext, aClass, aMethodName, aSignature);
}
Also used : BytecodeTypeRef(de.mirkosertic.bytecoder.core.BytecodeTypeRef) BytecodeMethodSignature(de.mirkosertic.bytecoder.core.BytecodeMethodSignature) BytecodeObjectTypeRef(de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef) BytecodeLinkerContext(de.mirkosertic.bytecoder.core.BytecodeLinkerContext) BytecodeArrayTypeRef(de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef) BytecodeMethod(de.mirkosertic.bytecoder.core.BytecodeMethod) BytecodeLinkedClass(de.mirkosertic.bytecoder.core.BytecodeLinkedClass) BytecodeLinkedClass(de.mirkosertic.bytecoder.core.BytecodeLinkedClass)

Aggregations

BytecodeArrayTypeRef (de.mirkosertic.bytecoder.core.BytecodeArrayTypeRef)5 BytecodeMethodSignature (de.mirkosertic.bytecoder.core.BytecodeMethodSignature)5 BytecodeObjectTypeRef (de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef)4 BytecodeTypeRef (de.mirkosertic.bytecoder.core.BytecodeTypeRef)4 PrintWriter (java.io.PrintWriter)3 ArrayList (java.util.ArrayList)3 ConstantPool (de.mirkosertic.bytecoder.backend.ConstantPool)2 Address (de.mirkosertic.bytecoder.classlib.Address)2 BytecodeImportedLink (de.mirkosertic.bytecoder.core.BytecodeImportedLink)2 BytecodeLinkedClass (de.mirkosertic.bytecoder.core.BytecodeLinkedClass)2 BytecodeMethod (de.mirkosertic.bytecoder.core.BytecodeMethod)2 BytecodePrimitiveTypeRef (de.mirkosertic.bytecoder.core.BytecodePrimitiveTypeRef)2 BytecodeProgram (de.mirkosertic.bytecoder.core.BytecodeProgram)2 Compiler (com.google.javascript.jscomp.Compiler)1 CompilerOptions (com.google.javascript.jscomp.CompilerOptions)1 SourceFile (com.google.javascript.jscomp.SourceFile)1 Export (de.mirkosertic.bytecoder.api.Export)1 CompileOptions (de.mirkosertic.bytecoder.backend.CompileOptions)1 CompileResult (de.mirkosertic.bytecoder.backend.CompileResult)1 CompileTarget (de.mirkosertic.bytecoder.backend.CompileTarget)1