CIL (собственное имя для MSIL) и байт-код Java больше одинаковы, чем различаются. Хотя есть некоторые важные различия:
1) CIL был разработан с самого начала, чтобы служить целью для нескольких языков. Как таковая, она поддерживает гораздо более богатую систему типов, включая подписанные и неподписанные типы, типы значений, указатели, свойства, делегаты, события, обобщения, объектную систему с одним корнем и многое другое. CIL поддерживает функции, которые не требуются для исходных языков CLR (C # и VB.NET), такие как глобальные функции и оптимизация хвостового вызова . Для сравнения, байт-код Java был разработан как цель для языка Java и отражает многие из ограничений, найденных в самой Java. Было бы намного сложнее написать C или Scheme с использованием байт-кода Java.
2) CIL был разработан для легкой интеграции в нативные библиотеки и неуправляемый код
3) Байт-код Java был разработан для интерпретации или компиляции, в то время как CIL был спроектирован только с использованием JIT-компиляции. Тем не менее, первоначальная реализация Mono использовала интерпретатор вместо JIT.
4) CIL был разработан ( и указан ), чтобы иметь удобочитаемую и доступную для записи форму на ассемблере, которая отображается непосредственно в форму байт-кода. Я считаю, что байт-код Java (как следует из названия) должен был быть только машиночитаемым. Конечно, байт-код Java относительно легко декомпилируется обратно в исходную Java и, как показано ниже, он также может быть «разобран».
Я должен отметить, что JVM (большинство из них) более высокооптимизировано, чем CLR (любой из них). Таким образом, необработанная производительность может быть причиной предпочтения ориентации на байт-код Java. Это подробности реализации.
Некоторые люди говорят, что байт-код Java был разработан для мультиплатформенности, в то время как CIL был разработан только для Windows. Это не вариант. В .NET Framework есть некоторые "Windows" измы, но в CIL их нет.
Как пример пункта 4) выше, я недавно написал игрушечный компилятор Java для CIL. Если вы кормите этот компилятор следующей программой Java:
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 ;
}
}
мой компилятор выдаст следующий 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
}
}
Это действительная программа CIL, которую можно подавать в ассемблер CIL, например ilasm.exe
, для создания исполняемого файла. Как вы можете видеть, CIL - полностью читаемый и записываемый язык. Вы можете легко создавать действительные программы CIL в любом текстовом редакторе.
Вы также можете скомпилировать приведенную выше Java-программу с помощью компилятора javac
, а затем запустить полученные файлы классов через javap
"дизассемблер", чтобы получить следующее:
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
}
Вывод javap
не компилируется (насколько мне известно), но если вы сравните его с выводом CIL выше, вы увидите, что они очень похожи.