Differences between MSIL and Java bytecode?

前端 未结 8 1286
南笙
南笙 2020-12-07 08:08

I\'m new to .Net and I\'m trying to understand the basics first. What is the difference between MSIL and Java bytecode?

相关标签:
8条回答
  • 2020-12-07 09:11

    Serge Lidin authored a decent book on the details of MSIL: Expert .NET 2.0 IL Assembler. I also was able to pick up MSIL quickly by looking at simple methods using .NET Reflector and Ildasm (Tutorial).

    The concepts between MSIL and Java bytecode are very similar.

    0 讨论(0)
  • 2020-12-07 09:14

    CIL (the proper name for MSIL) and Java bytecode are more the same than they are different. There are some important differences though:

    1) CIL was designed from the beginning to serve as a target for multiple languages. As such, it supports a much richer type system including signed and unsigned types, value types, pointers, properties, delegates, events, generics, an object-system with a single root, and more. CIL supports features not required for the initial CLR languages (C# and VB.NET) such as global functions and tail-call optimizations. In comparision, Java bytecode was designed as a target for the Java language and reflects many of the constraints found in Java itself. It would be a lot harder to write C or Scheme using Java bytecode.

    2) CIL was designed to integrate easily into native libraries and unmanaged code

    3) Java bytecode was designed to be either interpreted or compiled while CIL was designed assuming JIT compilation only. That said, the initial implementation of Mono used an interpreter instead of a JIT.

    4) CIL was designed (and specified) to have a human readable and writable assembly language form that maps directly to the bytecode form. I believe that Java bytecode was (as the name implies) meant to be only machine readable. Of course, Java bytecode is relatively easily decompiled back to the original Java and, as shown below, it can also be "disassembled".

    I should note that the JVM (most of them) is more highly optimized than the CLR (any of them). So, raw performance might be a reason to prefer targeting Java bytecode. This is an implementation detail though.

    Some people say that the Java bytecode was designed to be multi-platform while CIL was designed to be Windows only. This is not the case. There are some "Windows"isms in the .NET framework but there are none in CIL.

    As an example of point number 4) above, I wrote a toy Java to CIL compiler a while back. If you feed this compiler the following Java program:

    class Factorial{
        public static void main(String[] a){
        System.out.println(new Fac().ComputeFac(10));
        }
    }
    
    class Fac {
        public int ComputeFac(int num){
        int num_aux ;
        if (num < 1)
            num_aux = 1 ;
        else 
            num_aux = num * (this.ComputeFac(num-1)) ;
        return num_aux ;
        }
    }
    

    my compiler will spit out the following CIL:

    .assembly extern mscorlib { }
    .assembly 'Factorial' { .ver  0:0:0:0 }
    .class private auto ansi beforefieldinit Factorial extends [mscorlib]System.Object
    {
       .method public static default void main (string[] a) cil managed
       {
          .entrypoint
          .maxstack 16
          newobj instance void class Fac::'.ctor'()
          ldc.i4 3
          callvirt instance int32 class Fac::ComputeFac (int32)
          call void class [mscorlib]System.Console::WriteLine(int32)
          ret
       }
    }
    
    .class private Fac extends [mscorlib]System.Object
    {
       .method public instance default void '.ctor' () cil managed
       {
          ldarg.0
          call instance void object::'.ctor'()
          ret
       }
    
       .method public int32 ComputeFac(int32 num) cil managed
       {
          .locals init ( int32 num_aux )
          ldarg num
          ldc.i4 1
          clt
          brfalse L1
          ldc.i4 1
          stloc num_aux
          br L2
       L1:
          ldarg num
          ldarg.0
          ldarg num
          ldc.i4 1
          sub
          callvirt instance int32 class Fac::ComputeFac (int32)
          mul
          stloc num_aux
       L2:
          ldloc num_aux
          ret
       }
    }
    

    This is a valid CIL program that can be fed into a CIL assembler like ilasm.exe to create an executable. As you can see, CIL is a fully human readable and writable language. You can easily create valid CIL programs in any text editor.

    You can also compile the Java program above with the javac compiler and then run the resulting class files through the javap "disassembler" to get the following:

    class Factorial extends java.lang.Object{
    Factorial();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   return
    
    public static void main(java.lang.String[]);
      Code:
       0:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       3:   new #3; //class Fac
       6:   dup
       7:   invokespecial   #4; //Method Fac."<init>":()V
       10:  bipush  10
       12:  invokevirtual   #5; //Method Fac.ComputeFac:(I)I
       15:  invokevirtual   #6; //Method java/io/PrintStream.println:(I)V
       18:  return
    
    }
    
    class Fac extends java.lang.Object{
    Fac();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   return
    
    public int ComputeFac(int);
      Code:
       0:   iload_1
       1:   iconst_1
       2:   if_icmpge   10
       5:   iconst_1
       6:   istore_2
       7:   goto    20
       10:  iload_1
       11:  aload_0
       12:  iload_1
       13:  iconst_1
       14:  isub
       15:  invokevirtual   #2; //Method ComputeFac:(I)I
       18:  imul
       19:  istore_2
       20:  iload_2
       21:  ireturn
    }
    

    The javap output is not compilable (to my knowledge) but if you compare it to the CIL output above you can see that the two are very similar.

    0 讨论(0)
提交回复
热议问题