# Thesis notes I came with several ideas to how implement the problem 1. generate bytes in the straight way 2. use library that can generate classes https://github.com/raphw/byte-buddy/blob/master/README.md http://jni4net.com - call java methods from C# https://androidpaksquestions.blogspot.com/2016/04/step-by-step-java-jar-to-c-binding.html https://docs.microsoft.com/en-us/xamarin/android/platform/binding-java-library/ https://www.baeldung.com/java-asm - Guide to Java Bytecode manipulation with ASM https://asm.ow2.io/asm4-guide.pdf - ASM documentation and tutorials [pdf] https://github.com/saroff - the guy that previously made a thesis with similar topic https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html - some oracel documentation that might be useful https://stackoverflow.com/questions/29404600/java-bytecode-generation - question of the guy https://bytebuddy.net/#/ - another library for code generation Byte Buddy https://dzone.com/articles/generating-bytecode http://www.egtry.com/java/bytecode/asm/Hello - Hello World ASM tutorial http://www.egtry.com/java/index.html - куча примеров с ASM http://web.cs.ucla.edu/~msb/cs239-tutorial/ - еще туториал и объяснение ASM https://www.tiobe.com/tiobe-index/ - language rating I always use shadow types ## Add two integers ### Slang ``` Scala AddTwoIntegers(a: Integer, b: Integer): Integer do c is Integer c := a + b return c end ``` ### Opcodes ``` iload_0 iload_1 iadd istore_2 iload_2 ireturn ``` ### Java ASM ``` Java MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "addTwoIntegers", "(Ljava/lang/Integer;Ljava/lang/Integer;)java/lang/Integer", null, null); mv.visitCode(); mv.visitVarInsn(ILOAD, 0); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(IADD); mv.visitVarInsn(ISTORE, 2); mv.visitVarInsn(ILOAD, 2); mv.visitInsn(IRETURN); mv.visitMaxs(3, 3); mv.visitEnd(); ``` ### Java generated code ``` Java public static Long addTwoIntegers(Integer var0, Integer var1) { Object var2 = var0 + var1; return (Integer)var2; } ``` <!-- ## Subtract two integers ### Slang ``` Scala SubtractTwoIntegers(a: Integer, b: Integer): Integer do c is Integer c := a - b return c end ``` ### Opcodes ``` iload_0 iload_1 isub istore_2 iload_2 ireturn ``` ### Java ASM ``` Java MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "subtractTwoIntegers", "(Ljava/lang/Integer;Ljava/lang/Integer;)java/lang/Integer", null, null); mv.visitCode(); mv.visitVarInsn(ILOAD, 0); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(ISUB); mv.visitVarInsn(ISTORE, 2); mv.visitVarInsn(ILOAD, 2); mv.visitInsn(IRETURN); mv.visitMaxs(3, 3); mv.visitEnd(); ``` ### Java generated code ``` Java public static Integer addTwoIntegers(Integer var0, Integer var1) { Object var2 = var0 - var1; return (Integer)var2; } ``` ## Add two Reals For real in Slang - Double in Java ### Slang ``` Scala AddTwoReals(a: Real, b: Real): Real do c is Real c := a + b return c end ``` ### Opcodes ``` dload_0 dload_1 dadd dstore_2 dload_2 dreturn ``` ### Java ASM ``` Java MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "addTwoReals", "(Ljava/lang/Double;Ljava/lang/Double;)java/lang/Double", null, null); mv.visitCode(); mv.visitVarInsn(DLOAD, 0); mv.visitVarInsn(DLOAD, 1); mv.visitInsn(DADD); mv.visitVarInsn(DSTORE, 2); mv.visitVarInsn(DLOAD, 2); mv.visitInsn(DRETURN); mv.visitMaxs(3, 3); mv.visitEnd(); ``` ### Java generated code ``` Java public static Double addTwoReals(Double var0, Double var1) { Object var2 = var0 + var1; return (Double)var2; } ``` ## Subtract two Reals ``` Scala SubtractTwoReals(a: Real, b: Real): Real do c is Real c := a - b return c end ``` ### Opcodes ``` dload_0 dload_1 dsub dstore_2 dload_2 dreturn ``` ### Java ASM ``` Java MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "subtractTwoReals", "(Ljava/lang/Double;Ljava/lang/Double;)java/lang/Double", null, null); mv.visitCode(); mv.visitVarInsn(DLOAD, 0); mv.visitVarInsn(DLOAD, 1); mv.visitInsn(DSUB); mv.visitVarInsn(DSTORE, 2); mv.visitVarInsn(DLOAD, 2); mv.visitInsn(DRETURN); mv.visitMaxs(3, 3); mv.visitEnd(); ``` ### Java generated code ``` Java public static Double subtractTwoReals(Double var0, Double var1) { Object var2 = var0 - var1; return (Double)var2; } ``` --> ## Simple Unit declaration ### Slang ``` Scala unit SimpleObject value: Integer init(value: Integer) do this.value = value end end ``` ### Opcode TODO ``` aload_0 iload_1 putfield return ``` ### Java ASM ``` Java ClassWriter cw = new ClassWriter(0); cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "gen/SimpleObject", null, "java/lang/Object", null); cw.visitField(ACC_PUBLIC, "value", "Ljava/lang/Integer;", null, null).visitEnd(); //default constructor { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/Integer;)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ILOAD, 1); mv.visitFieldInsn(PUTFIELD, "gen/SimpleObject", "value", "Ljava/lang/Integer;"); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } cw.visitEnd(); ``` ### Java generated code ``` Java package gen; public class SimpleObject { public Integer value; public SimpleObject(Integer var1) { this.value = var1; } } ``` ## Working with several units ### Slang ``` Scala AddTwoObjects(a: SimpleObject, b: SimpleObject): SimpleObject do c is SimpleObject cTemp is Integer cTemp := a.value + b.value c := SimpleObject(cTemp) return c end ``` ### Opcode ``` aload_1 getfield isore_3 aload_2 getfield istore_4 iload_3 iload_4 iadd istore_5 new dup iload_5 invokespecial areturn ``` ### Java ASM ``` Java MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "AddTwoObjects", "(Lgen/SimpleObject;Lgen/SimpleObject;)gen/SimpleObject", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD, "gen/SimpleObject", "value", "Ljava/lang/Integer;"); mv.visitVarInsn(ISTORE, 3); mv.visitVarInsn(ALOAD, 2); mv.visitFieldInsn(GETFIELD, "gen/SimpleObject", "value", "Ljava/lang/Integer;"); mv.visitVarInsn(ISTORE, 4); mv.visitVarInsn(ILOAD, 3); mv.visitVarInsn(ILOAD, 4); mv.visitInsn(IADD); mv.visitVarInsn(ISTORE, 5); mv.visitTypeInsn(NEW, "Lgen/SimpleObject;"); mv.visitInsn(DUP); mv.visitVarInsn(ILOAD,5); mv.visitMethodInsn(INVOKESPECIAL, "gen/SimpleObject", "<init>", "(Ljava/lang/Integer;)V"); mv.visitInsn(ARETURN); mv.visitEnd(); ``` ### Java generated code ``` Java public SimpleObject AddTwoObjects(SimpleObject var1, SimpleObject var2) { Integer var3 = var1.value; Integer var4 = var2.value; Object var5 = var3 + var4; return new SimpleObject((Integer)var5); } ``` ## Boolean check ### Slang ``` Scala a is Integer b is Integer c is Boolean a := 1 b := a + 2 c := a == b ``` ### Opcode ``` TODO iconst_1 invokestatic astore_1 iconst_2 aload_1 invokevirtual iadd invokestatic astore_2 aload_1 aload_2 //label 3 if_acmpne label3 iconst_1 //label 4 goto label4 //visit label 3 f_append//CHECK iconst_0 //visit label 4 invokestatic asstore_3 return ``` ### Java ASM ``` Java methodVisitor.visitInsn(ICONST_1); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitVarInsn(ASTORE, 1); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(IADD); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitVarInsn(ASTORE, 2); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitVarInsn(ALOAD, 2); Label label3 = new Label(); methodVisitor.visitJumpInsn(IF_ACMPNE, label3); methodVisitor.visitInsn(ICONST_1); Label label4 = new Label(); methodVisitor.visitJumpInsn(GOTO, label4); methodVisitor.visitLabel(label3); methodVisitor.visitFrame(Opcodes.F_APPEND, 2, new Object[]{"java/lang/Integer", "java/lang/Integer"}, 0, null); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitLabel(label4); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); methodVisitor.visitVarInsn(ASTORE, 3); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(2, 4); methodVisitor.visitEnd(); ``` ### Java generated code ``` Java Integer var1 = 1; Integer var2 = 2 + var1; Boolean var3 = var1 == var2; ``` ## Loop ## IfElse # Complex Cases ## Fibonacci ### Slang ``` Scala fib_recursive(n: Integer): Integer do if n < 2 do return n else return recursive(n - 1) + recursive(n - 2) end end // optimized speed, but increased memory consumption fib_recursive_memo(n: Integer): Integer do inner(prvprv: Integer, prv: Integer, c Integer): Integer do if c < 1 do return prvprv else do return inner(prv, prvprv + prv, c - 1) end end return inner(0, 1, n) end fib_iterative(n: Integer): Integer do current is 0 next is 1 temp: Integer require n > 0 do n = n - 1 temp = current + next current = next next = temp end return next end ``` ### Opcode ``` //fib_recursive ``` ### Java ASM ``` Java { //fib_recursive methodVisitor = classWriter.visitMethod(0, "fib_recursive", "(Ljava/lang/Integer;)Ljava/lang/Integer;", null, null); methodVisitor.visitCode(); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitLineNumber(6, label0); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(ICONST_2); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); Label label2 = new Label(); methodVisitor.visitLabel(label2); methodVisitor.visitLineNumber(7, label2); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitInsn(ARETURN); methodVisitor.visitLabel(label1); methodVisitor.visitLineNumber(9, label1); methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "gen/Fibonacci", "fib_recursive", "(Ljava/lang/Integer;)Ljava/lang/Integer;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(ICONST_2); methodVisitor.visitInsn(ISUB); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "gen/Fibonacci", "fib_recursive", "(Ljava/lang/Integer;)Ljava/lang/Integer;", false); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(IADD); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitInsn(ARETURN); Label label3 = new Label(); methodVisitor.visitLabel(label3); methodVisitor.visitLocalVariable("this", "Lgen/Fibonacci;", null, label0, label3, 0); methodVisitor.visitLocalVariable("n", "Ljava/lang/Integer;", null, label0, label3, 1); methodVisitor.visitMaxs(4, 2); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PRIVATE, "inner", "(Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", null, null); methodVisitor.visitCode(); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitLineNumber(13, label0); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(ICONST_1); Label label1 = new Label(); methodVisitor.visitJumpInsn(IF_ICMPGE, label1); Label label2 = new Label(); methodVisitor.visitLabel(label2); methodVisitor.visitLineNumber(14, label2); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitInsn(ARETURN); methodVisitor.visitLabel(label1); methodVisitor.visitLineNumber(16, label1); methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(IADD); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitMethodInsn(INVOKESPECIAL, "gen/Fibonacci", "inner", "(Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", false); methodVisitor.visitInsn(ARETURN); Label label3 = new Label(); methodVisitor.visitLabel(label3); methodVisitor.visitLocalVariable("this", "Lgen/Fibonacci;", null, label0, label3, 0); methodVisitor.visitLocalVariable("prvprv", "Ljava/lang/Integer;", null, label0, label3, 1); methodVisitor.visitLocalVariable("prv", "Ljava/lang/Integer;", null, label0, label3, 2); methodVisitor.visitLocalVariable("c", "Ljava/lang/Integer;", null, label0, label3, 3); methodVisitor.visitMaxs(5, 4); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(0, "fib_recursive_memo", "(Ljava/lang/Integer;)Ljava/lang/Integer;", null, null); methodVisitor.visitCode(); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitLineNumber(20, label0); methodVisitor.visitVarInsn(ALOAD, 0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitMethodInsn(INVOKESPECIAL, "gen/Fibonacci", "inner", "(Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;", false); methodVisitor.visitInsn(ARETURN); Label label1 = new Label(); methodVisitor.visitLabel(label1); methodVisitor.visitLocalVariable("this", "Lgen/Fibonacci;", null, label0, label1, 0); methodVisitor.visitLocalVariable("n", "Ljava/lang/Integer;", null, label0, label1, 1); methodVisitor.visitMaxs(4, 2); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(0, "fib_iterative", "(Ljava/lang/Integer;)Ljava/lang/Integer;", null, null); methodVisitor.visitCode(); Label label0 = new Label(); methodVisitor.visitLabel(label0); methodVisitor.visitLineNumber(24, label0); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitVarInsn(ASTORE, 2); Label label1 = new Label(); methodVisitor.visitLabel(label1); methodVisitor.visitLineNumber(25, label1); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitVarInsn(ASTORE, 3); Label label2 = new Label(); methodVisitor.visitLabel(label2); methodVisitor.visitLineNumber(26, label2); methodVisitor.visitInsn(ACONST_NULL); methodVisitor.visitVarInsn(ASTORE, 4); Label label3 = new Label(); methodVisitor.visitLabel(label3); methodVisitor.visitLineNumber(28, label3); methodVisitor.visitFrame(Opcodes.F_APPEND,3, new Object[] {"java/lang/Integer", "java/lang/Integer", "java/lang/Integer"}, 0, null); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); Label label4 = new Label(); methodVisitor.visitJumpInsn(IFLE, label4); Label label5 = new Label(); methodVisitor.visitLabel(label5); methodVisitor.visitLineNumber(29, label5); methodVisitor.visitVarInsn(ALOAD, 1); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(ICONST_1); methodVisitor.visitInsn(ISUB); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitVarInsn(ASTORE, 1); Label label6 = new Label(); methodVisitor.visitLabel(label6); methodVisitor.visitLineNumber(30, label6); methodVisitor.visitVarInsn(ALOAD, 2); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); methodVisitor.visitInsn(IADD); methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); methodVisitor.visitVarInsn(ASTORE, 4); Label label7 = new Label(); methodVisitor.visitLabel(label7); methodVisitor.visitLineNumber(31, label7); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitVarInsn(ASTORE, 2); Label label8 = new Label(); methodVisitor.visitLabel(label8); methodVisitor.visitLineNumber(32, label8); methodVisitor.visitVarInsn(ALOAD, 4); methodVisitor.visitVarInsn(ASTORE, 3); methodVisitor.visitJumpInsn(GOTO, label3); methodVisitor.visitLabel(label4); methodVisitor.visitLineNumber(35, label4); methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); methodVisitor.visitVarInsn(ALOAD, 3); methodVisitor.visitInsn(ARETURN); Label label9 = new Label(); methodVisitor.visitLabel(label9); methodVisitor.visitLocalVariable("this", "Lgen/Fibonacci;", null, label0, label9, 0); methodVisitor.visitLocalVariable("n", "Ljava/lang/Integer;", null, label0, label9, 1); methodVisitor.visitLocalVariable("current", "Ljava/lang/Integer;", null, label1, label9, 2); methodVisitor.visitLocalVariable("next", "Ljava/lang/Integer;", null, label2, label9, 3); methodVisitor.visitLocalVariable("temp", "Ljava/lang/Integer;", null, label3, label9, 4); methodVisitor.visitMaxs(2, 5); methodVisitor.visitEnd(); } ``` ##